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
原文地址:https://www.cnblogs.com/Opaser/p/4318674.html