Uva 11324 The Largest Clique【强连通 DAG动规 spfa】

白书上的例题

做一遍tarjan后,缩点,每一个scc节点的权为它的结点数,做一次DAG上的动规,求出路径上的最大点权和,就可以了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 using namespace std;
  8 
  9 const int maxn = 5005;
 10 int n,m;
 11 int first[maxn];
 12 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
 13 int scnt,ecnt,dfs_clock;
 14 int dp[maxn];
 15 
 16 int first1[maxn];
 17 int ecnt1;
 18 
 19 struct Edge{
 20     int v,next;
 21 }e[maxn*10];
 22 
 23 Edge e1[maxn*10];
 24 
 25 stack<int> S;
 26 
 27 void init(){
 28     ecnt = ecnt1 = 0;
 29     memset(first,-1,sizeof(first));
 30     memset(first1,-1,sizeof(first1));
 31     memset(dp,0,sizeof(dp));
 32 }
 33 
 34 void addedges(int u,int v){
 35     e[ecnt].v = v;
 36     e[ecnt].next = first[u];
 37     first[u] = ecnt++;
 38 }
 39 
 40 void addedges1(int u,int v){
 41     e1[ecnt1].v = v;
 42     e1[ecnt1].next = first1[u];
 43     first1[u] = ecnt1++;
 44 }
 45 
 46 void dfs(int u){
 47     low[u] = pre[u] = ++dfs_clock;
 48     S.push(u);
 49     for(int i = first[u];~i;i = e[i].next){
 50         int v = e[i].v;
 51         if(!pre[v]){
 52             dfs(v);
 53             low[u] = min(low[u],low[v]);
 54         }
 55         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 56     }
 57     if(pre[u] == low[u]){
 58         scnt++;
 59         for(;;){
 60             int x = S.top();S.pop();
 61             sc[x] = scnt;
 62             scn[scnt]++;
 63             if(x == u) break;
 64         }
 65     }
 66 }
 67 
 68 void find_scc(){
 69     while(!S.empty()) S.pop();
 70     scnt = dfs_clock = 0;
 71     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 72     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
 73     
 74     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 75 }
 76 
 77 int solve(int p){
 78     if(dp[p]) return dp[p];
 79     for(int i = first1[p];~i;i = e1[i].next){
 80         int v = e1[i].v;
 81         dp[p] = max(dp[p],solve(v));
 82     }
 83     return dp[p] = dp[p] + scn[p];
 84 }
 85 
 86 
 87 int main(){
 88     int T;
 89     scanf("%d",&T);
 90     while(T--){
 91         init();
 92         scanf("%d %d",&n,&m);
 93         for(int i = 0;i < m;i++ ){
 94             int u,v;
 95             scanf("%d %d",&u,&v);
 96             addedges(u,v);
 97         }
 98         find_scc();
 99         
100         for(int u = 1;u <= n;u++){
101             for(int i = first[u];~i;i = e[i].next){
102                 int v = e[i].v;
103                 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]);
104             }
105         }
106         
107 
108         int ans = 0;
109         for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i));
110         printf("%d
",ans);
111     }
112     return 0;
113 }
View Code


还有另一种做法是,建立一个超级源点,与入度为0的scc节点连接,做一次spfa,求出路径上的最大点权和

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 #include<queue>
  8 using namespace std;
  9 
 10 const int maxn = 5005;
 11 const int INF = 1000000005;
 12 int n,m;
 13 int first[maxn];
 14 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
 15 int scnt,ecnt,dfs_clock;
 16 int dp[maxn];
 17 
 18 int du[maxn];
 19 int dis[maxn];
 20 int inq[maxn];
 21 
 22 int first1[maxn];
 23 int ecnt1;
 24 
 25 struct Edge{
 26     int v,next;
 27 }e[maxn*10];
 28 
 29 Edge e1[maxn*10];
 30 
 31 stack<int> S;
 32 vector<int> g[maxn];
 33 int val[maxn];
 34 
 35 void init(){
 36     ecnt = ecnt1 = 0;
 37     memset(first,-1,sizeof(first));
 38     memset(val,0,sizeof(val));
 39     memset(du,0,sizeof(du));       
 40 }
 41 
 42 void addedges(int u,int v){
 43     e[ecnt].v = v;
 44     e[ecnt].next = first[u];
 45     first[u] = ecnt++;
 46 }
 47 
 48 void dfs(int u){
 49     low[u] = pre[u] = ++dfs_clock;
 50     S.push(u);
 51     for(int i = first[u];~i;i = e[i].next){
 52         int v = e[i].v;
 53         if(!pre[v]){
 54             dfs(v);
 55             low[u] = min(low[u],low[v]);
 56         }
 57         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 58     }
 59     if(pre[u] == low[u]){
 60         scnt++;
 61         for(;;){
 62             int x = S.top();S.pop();
 63             sc[x] = scnt;
 64             val[scnt]++;
 65             if(x == u) break;
 66         }
 67     }
 68 }
 69 
 70 void find_scc(){
 71     while(!S.empty()) S.pop();
 72     scnt = dfs_clock = 0;
 73     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 74     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
 75     
 76     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 77 }
 78 
 79 
 80 int spfa(){  
 81     memset(inq, 0, sizeof(inq));  
 82     queue<int>q;  
 83     g[0].clear();  
 84     q.push(0);  
 85     dis[0] = 0; val[0] = 0;  
 86     for(int i = 1; i <= scnt; i++){if(du[i] == 0)g[0].push_back(i); dis[i] = -INF;}  
 87     int ans = 0;  
 88     while(!q.empty()){  
 89         int u = q.front(); q.pop(); inq[u] = 0;  
 90         for(int i = 0; i < g[u].size(); i++){  
 91             int v = g[u][i];  
 92             if(dis[v] < dis[u] + val[v]){  
 93                 dis[v] = dis[u] + val[v];  
 94                 ans = max(ans, dis[v]);  
 95                 if(inq[v] == 0)inq[v] = 1, q.push(v);  
 96             }  
 97         }  
 98     }  
 99     return ans;  
100 }  
101 
102 int main(){
103     int T;
104     scanf("%d",&T);
105     while(T--){
106         init();
107         scanf("%d %d",&n,&m);
108         for(int i = 0;i < m;i++ ){
109             int u,v;
110             scanf("%d %d",&u,&v);
111             addedges(u,v);
112         }
113         find_scc();
114         for(int i = 1;i <= scnt;i++) g[i].clear();
115     
116         for(int u = 1;u <= n;u++){
117             for(int i = first[u];~i;i = e[i].next){
118                 int v = e[i].v;
119                 if(sc[u] != sc[v]) g[sc[u]].push_back(sc[v]),du[sc[v]]++;
120             }
121         }
122         printf("%d
",spfa());
123     }
124     return 0;
125 }
View Code
原文地址:https://www.cnblogs.com/wuyuewoniu/p/4700227.html