zoukankan      html  css  js  c++  java
  • uva11324 有向图的强连通分量+记忆化dp

    给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以)。

    因为整张图可能存在环路,所以不好使用dp直接做,先采用有向图的强连通分量,进行缩点,然后得到一个有向无环图(DAG) 在采用记忆话dp 去做即可

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string.h>
    #include <vector>
    #include <stack>
    using namespace std;
    const int maxn = 1000+10;
    vector<int>G[maxn];
    int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
    stack<int> S;
    void dfs(int u){
        pre[u] = lowlink[u]=++dfs_clock;
        S.push(u);
        for(int i=0; i<G[u].size() ; ++i){
             int v = G[u][i];
             if(!pre[v]){
                 dfs(v);
                 lowlink[u] = min(lowlink[u], lowlink[v]);
             }else if(!sccno[v]){
                 lowlink[u] = min(lowlink[u],pre[v]);
             }
        }
        if(lowlink[u]==pre[u]){
            scc_cnt++;
            for(;;){
                int x = S.top(); S.pop();
                sccno[x] = scc_cnt;
                if(x==u)break;
            }
        }
    }
    void find_scc(int n){
         dfs_clock =scc_cnt =0;
         memset(sccno,0,sizeof(sccno));
         memset(pre, 0, sizeof(pre));
         while(!S.empty())S.pop();
         for(int i=0; i<n; ++i)
            if(!pre[i]) dfs(i);
    }
    int value[maxn],dp[maxn];
    vector<int> E[maxn];
    int dff(int u){
        if(dp[u]!=-1) return dp[u];
         dp[u]=0;
        for(int i=0; i<E[u].size(); ++i){
             int v = E[u][i];
             dp[u]=max(dff(v),dp[u]);
        }
        dp[u]+=value[u];
        return dp[u];
    }
    int main()
    {
         int cas;
         scanf("%d",&cas);
         for(int cc =1; cc<=cas; ++cc){
    
               int n,m;
               scanf("%d%d",&n,&m);
               for(int i=0; i<=n; ++i)
                G[i].clear(),E[i].clear();
               for(int i=1; i<=m; ++i){
                   int u,v;
                   scanf("%d%d",&u,&v);
                   u--; v--;
                   G[u].push_back(v);
               }
               find_scc(n);
               memset(value,0,sizeof(value));
               for(int u=0; u<n; ++u){
                    value[sccno[u]]++;
                    for(int j=0; j<G[u].size(); ++j){
                         int v=G[u][j];
                         if(sccno[u]!=sccno[v]){
                              E[sccno[u]].push_back(sccno[v]);
                         }
                    }
               }
               memset(dp , -1 , sizeof(dp));
               int ans=0;
               for(int i=1; i <= scc_cnt; ++i){
                    if(dp[i]==-1)
                     dff(i);
                     ans=max(ans,dp[i]);
               }
               printf("%d
    ",ans);
         }
        return 0;
    }
    View Code
  • 相关阅读:
    闪回还原点解析
    先有鸡还是先有蛋的争论
    Android缓存处理
    hdu 1398 Square Coins (母函数)
    JSON具体解释
    【LeetCode】String to Integer (atoi) 解题报告
    【Linux探索之旅】第一部分第四课:磁盘分区,并完毕Ubuntu安装
    MySQL排序:SELECT ORDER BY
    架构师速成7.3-devops为什么非常重要
    升级Linux内核导致vmware无法使用(vmnet模块无法编译)解决方式
  • 原文地址:https://www.cnblogs.com/Opaser/p/4318674.html
Copyright © 2011-2022 走看看