zoukankan      html  css  js  c++  java
  • BZOJ 1194: [HNOI2006]潘多拉的盒子( BFS + tarjan + dp )

    O(S²)枚举2个诅咒机, 然后O(n²)BFS去判断. 构成一个有向图, tarjan缩点, 然后就是求DAG的最长路.. 

    -----------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
     
    using namespace std;
     
    const int maxn = 59;
     
    typedef pair<int, int> pii;
     
    struct edge {
    int to;
    edge* next;
    } E[10000], *pt = E, *head[maxn];
     
    void addedge(int u, int v) {
    pt->to = v; pt->next = head[u]; head[u] = pt++;
    }
     
    struct O {
    int n, p[maxn][2];
    bool F[maxn];
    void init() {
    memset(F, 0, sizeof F);
    int m; scanf("%d%d", &n, &m);
    while(m--) {
    int t; scanf("%d", &t);
    F[t] = true;
    }
    for(int i = 0; i < n; i++)
    scanf("%d%d", p[i], p[i] + 1);
    }
    } o[maxn];
      

    int N, T = 0, n = 0, CK = 0, vis[maxn][maxn];

    int dfn[maxn], low[maxn], scc[maxn], w[maxn];
    queue<pii> q;
    stack<int> S;
     
    void tarjan(int x) {
    dfn[x] = low[x] = ++CK;
    S.push(x);
    for(edge* e = head[x]; e; e = e->next) if(!dfn[e->to]) {
    tarjan(e->to);
    low[x] = min(low[x], low[e->to]);
    } else if(!~scc[e->to])
    low[x] = min(low[x], dfn[e->to]);
    if(dfn[x] == low[x]) {
    int t;
    do {
    t = S.top(); S.pop();
    w[scc[t] = n]++;
    } while(t != x);
    n++;
    }
    }
     
    bool BFS(int A, int B) {
    T++;
    O &a = o[A], &b = o[B];
    while(!q.empty()) q.pop(); q.push(make_pair(0, 0));
    while(!q.empty()) {
    pii o = q.front(); q.pop();
    for(int i = 0; i < 2; i++) {
    int x = a.p[o.first][i], y = b.p[o.second][i];
    if(vis[x][y] == T) continue;
    if(!a.F[x] && b.F[y]) return false;
    vis[x][y] = T;
    q.push(make_pair(x, y));
    }
    }
    return true;
    }
      

    namespace G {

    edge* head[maxn];
    int deg[maxn], ans[maxn];
    void addedge(int u, int v) {
    pt->to = v; pt->next = head[u]; head[u] = pt++;
    }
    void init() {
    for(int x = 0; x < N; x++)
    for(edge* e = ::head[x]; e; e = e->next) 
    if(scc[x] != scc[e->to]) addedge(scc[x], scc[e->to]);
    }
    void dfs(int x) {
    if(ans[x]) return;
    for(edge* e = head[x]; e; e = e->next) {
    dfs(e->to);
    ans[x] = max(ans[x], ans[e->to]);
    }
    ans[x] += w[x];
    }
    void solve() {
    init();
    memset(ans, 0, sizeof ans);
    for(int i = 0; i < n; i++) dfs(i);
    printf("%d ", *max_element(ans, ans + n));
    }
    }
     
    int main() {

      

    scanf("%d", &N);
    for(int i = 0; i < N; i++) o[i].init();
    for(int i = 0; i < N; i++)
    for(int j = 0; j < N; j++)
    if(i != j && BFS(i, j)) addedge(i, j);
    memset(dfn, 0, sizeof dfn);
    memset(scc, -1, sizeof scc);
    memset(w, 0, sizeof w);
    for(int i = 0; i < N; i++) if(!dfn[i]) tarjan(i);
    G::solve();
    return 0;
    }

    -----------------------------------------------------------------------------

    1194: [HNOI2006]潘多拉的盒子

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 241  Solved: 127
    [Submit][Status][Discuss]

    Description

     

    Input

    第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50)。文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语机S-1的顺序描述。每一块的格式如下。 一块的第一行有两个正整数n,m。分别表示该咒语机中元件的个数、咒语源输出元的个数(1≤m≤n≤50)。 接下来一行有m个数,表示m个咒语源输出元的标号(都在0到n-1之间)。接下来有n行,每一行两个数。第i行(0≤i≤n-1)的两个数表示pi,0和pi,1(当然,都在0到n-1之间)。

    Output

    第一行有一个正整数t,表示最长升级序列的长度。

    Sample Input

    4
    1 1
    0
    0 0
    2 1
    0
    1 1
    0 0
    3 1
    0
    1 1
    2 2
    0 0
    4 1
    0
    1 1
    2 2
    3 3
    0 0

    Sample Output

    3

    HINT

    Source

  • 相关阅读:
    package、import、java及javac的相关介绍(转)
    Android开发之大位图二次採样压缩处理(源码分享)
    ubuntu 14.04 使用极点五笔输入法
    HBase概念学习(七)HBase与Mapreduce集成
    JS中setTimeout()的使用方法具体解释
    IntelliJ Idea 经常使用快捷键列表
    公有云与私有云的差别(转)
    jbpm入门样例
    android之PackageManager简单介绍
    WebService究竟是什么?
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4933379.html
Copyright © 2011-2022 走看看