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 }