HDU-2767-tarjan/Kosaraju求scc

http://acm.hdu.edu.cn/showproblem.php?pid=2767

问最少添加几条边使得图为强连通。

  tarjan跑一下,然后对强连通分量缩点,找下此时出度为零和入度为零的点数输出较大者即可。

  tarjan,dfn数组也同时起到了标记的作用,如果未标记说明此时的边就是dfs树上的边,否则的话,如果v已经处于某个scc中说明这条边是交叉边,不用考虑(因为一定无对应的回边,有的话这个点就应该和v属于同一个scc,与过程矛盾)。否则就是回边了,和求桥和割点的方法类似求dfn以及low数组。

  最后如果low[u]==dfn[u]说明u沿着他的孩子能回到他自己,这就形成了一个环,环上的所有点构成了一个scc,不断出栈直到u出现为止统计下scc。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<map>
  5 #include<set>
  6 #include<stack>
  7 #include<deque>
  8 #include<bitset>
  9 #include<unordered_map>
 10 #include<unordered_set>
 11 #include<queue>
 12 #include<cstdlib>
 13 #include<ctype.h>
 14 #include<ctime>
 15 #include<functional>
 16 #include<algorithm>
 17 #include<bits/stdc++.h>
 18 using namespace std;
 19 #define LL long long 
 20 #define pii pair<int,int>
 21 #define mp make_pair
 22 #define pb push_back
 23 #define fi first
 24 #define se second
 25 #define inf 0x3f3f3f3f
 26 #define debug puts("debug")
 27 #define mid ((L+R)>>1)
 28 #define lc (id<<1)
 29 #define rc (id<<1|1)
 30 const int maxn=20020;
 31 const int maxm=200020;
 32 const double PI=acos(-1.0);
 33 const double eps=1e-6;
 34 const LL mod=1e9+7;
 35 LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
 36 LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
 37 LL qpow(LL a,LL b,LL c){LL r=1; for(;b;b>>=1,a=a*a%c)if(b&1)r=r*a%c;return r;}
 38 template<class T>
 39 void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
 40 struct Edge{int u,v,w,next;};
 41 
 42 int dfn[maxn],low[maxn],scc[maxn],scc_cnt,sum;
 43 int in[maxn],out[maxn];
 44 vector<int>g[maxn];
 45 stack<int>S;
 46 void dfs(int u){
 47     dfn[u]=low[u]=++sum;
 48     S.push(u);
 49     for(int v:g[u]){
 50         if(!dfn[v]){
 51             dfs(v);
 52             low[u]=min(low[u],low[v]);
 53         }else if(!scc[v]){
 54             low[u]=min(low[u],dfn[v]);
 55         }
 56     }
 57     if(dfn[u]==low[u]){
 58         ++scc_cnt;
 59         int x=-1;
 60         for(;;){
 61             x=S.top();S.pop();
 62             scc[x]=scc_cnt;
 63             if(x==u)break;
 64         }
 65     }
 66 }
 67 int main(){
 68     int t,n,m,i,j,k,u,v;
 69     scanf("%d",&t);
 70     while(t--){
 71         scanf("%d%d",&n,&m);
 72         for(i=1;i<=n;++i)g[i].clear(),dfn[i]=low[i]=scc[i]=0;
 73         sum=scc_cnt=0;
 74         while(!S.empty())S.pop();
 75         while(m--){
 76             scanf("%d%d",&u,&v);
 77             g[u].pb(v);
 78         }
 79         for(i=1;i<=n;++i){
 80             if(!dfn[i]){
 81                 dfs(i);
 82             }
 83         }
 84         if(scc_cnt==1){
 85             cout<<0<<endl;
 86             continue;
 87         }
 88         for(i=1;i<=scc_cnt;++i)in[i]=out[i]=1;
 89         for(u=1;u<=n;++u){
 90             for(int v:g[u]){
 91                 if(scc[u]!=scc[v]){
 92                     in[scc[v]]=out[scc[u]]=0;
 93                 }
 94             }
 95         }
 96         int a=0,b=0;
 97         for(i=1;i<=scc_cnt;++i)a+=in[i],b+=out[i];
 98         cout<<max(a,b)<<endl;
 99     }
100     return 0;
101 }

Kosaraju:先按原图跑一编按后序顺序编号,然后按照编号从大到小跑反向图,跑一次就是一个scc。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<map>
 5 #include<set>
 6 #include<stack>
 7 #include<deque>
 8 #include<bitset>
 9 #include<unordered_map>
10 #include<unordered_set>
11 #include<queue>
12 #include<cstdlib>
13 #include<ctype.h>
14 #include<ctime>
15 #include<functional>
16 #include<algorithm>
17 #include<bits/stdc++.h>
18 using namespace std;
19 #define LL long long 
20 #define pii pair<int,int>
21 #define mp make_pair
22 #define pb push_back
23 #define fi first
24 #define se second
25 #define inf 0x3f3f3f3f
26 #define debug puts("debug")
27 #define mid ((L+R)>>1)
28 #define lc (id<<1)
29 #define rc (id<<1|1)
30 const int maxn=20020;
31 const int maxm=200020;
32 const double PI=acos(-1.0);
33 const double eps=1e-6;
34 const LL mod=1e9+7;
35 LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
36 LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
37 LL qpow(LL a,LL b,LL c){LL r=1; for(;b;b>>=1,a=a*a%c)if(b&1)r=r*a%c;return r;}
38 template<class T>
39 void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
40 struct Edge{int u,v,w,next;};
41 
42 int vis[maxn],scc[maxn],scc_cnt;
43 int in[maxn],out[maxn];
44 vector<int>g[maxn],g2[maxn],q;
45 void dfs1(int u){
46     if(vis[u])return;vis[u]=1;
47     for(int v:g[u])dfs1(v);q.pb(u);
48 }
49 void dfs2(int u){
50     if(scc[u])return;scc[u]=scc_cnt;
51     for(int v:g2[u])dfs2(v);
52 }
53 int main(){
54     int t,n,m,i,j,k,u,v;
55     scanf("%d",&t);
56     while(t--){
57         scanf("%d%d",&n,&m);
58         q.clear();
59         for(i=1;i<=n;++i)g[i].clear(),g2[i].clear(),vis[i]=scc[i]=0;
60         scc_cnt=0;
61         while(m--){
62             scanf("%d%d",&u,&v);
63             g[u].pb(v);
64             g2[v].pb(u);
65         }
66         for(i=1;i<=n;++i){
67             if(!vis[i]){
68                 dfs1(i);
69             }
70         }
71         for(i=n-1;i>=0;--i){
72             if(!scc[q[i]]){
73                 ++scc_cnt;
74                 dfs2(q[i]);
75             }
76         }
77     //    cout<<"FUCK: "<<scc_cnt<<endl;
78          if(scc_cnt==1){
79             cout<<0<<endl;
80             continue;
81         }
82         for(i=1;i<=scc_cnt;++i)in[i]=out[i]=1;
83         for(u=1;u<=n;++u){
84             for(int v:g[u]){
85                 if(scc[u]!=scc[v]){
86                     in[scc[v]]=out[scc[u]]=0;
87                 }
88             }
89         }
90         int a=0,b=0;
91         for(i=1;i<=scc_cnt;++i)a+=in[i],b+=out[i];
92         cout<<max(a,b)<<endl;
93         
94     }
95     return 0;
96 }
原文地址:https://www.cnblogs.com/zzqc/p/10072147.html