• 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

  • 相关阅读:
    英语语法总结---二、英语中的从句是怎么回事
    【Cocos得知】技术要点通常的积累
    政府采购清单应包括“问题” 积
    Ubuntu通过使用PyCharm 进行调试 Odoo 8.0 可能出现的问题
    Android自己定义组件系列【8】——面膜文字动画
    手机新闻网站,手持移动新闻,手机报client,jQuery Mobile手机新闻网站,手机新闻网站demo,新闻阅读器开发
    OS和android游戏纹理优化和内存优化(cocos2d-x)
    删除重复数据
    MyEclipse2014 设备 checkstyle、PMD、findbugs 最简单的方法 详细说明
    hdu5044 Tree 树链拆分,点细分,刚,非递归版本
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4933379.html
Copyright © 2020-2023  润新知