Tarjan+缩点【强连通分量】【模板】
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 const int maxn=100005;//边数 9 const int maxn1=1005;//顶点数 10 struct edge{ 11 int from; 12 int to; 13 int next; 14 }EDGE[maxn]; 15 vector<int>vc[maxn1]; 16 int head[maxn1],dfn[maxn1],vis[maxn1],low[maxn1],col[maxn1],out[maxn1],in[maxn1],en[maxn1],stk[maxn1];//各个变量的意义可参照上篇博客 17 int edge_cnt=0,tot1=0,tot2=0,scc_cnt=0,tot0=0; 18 void add(int x,int y) 19 { 20 EDGE[edge_cnt].from=x; 21 EDGE[edge_cnt].to=y; 22 EDGE[edge_cnt].next=head[x]; 23 head[x]=edge_cnt++; 24 } 25 void Tarjan(int u) 26 { 27 low[u]=dfn[u]=++tot1;//注意tot1的初值必须是1【因为dfn必须为正数】,所以这里使用++tot1而不用tot1++; 28 vis[u]=1; 29 stk[++tot2]=u; 30 for(int i = head[u]; i != -1 ; i = EDGE[i].next) 31 { 32 if(!dfn[EDGE[i].to]){ 33 Tarjan(EDGE[i].to); 34 low[u]=min(low[u],low[EDGE[i].to]); 35 } 36 else if(vis[EDGE[i].to]){ 37 low[u]=min(low[u],low[EDGE[i].to]); 38 } 39 } 40 if(low[u]==dfn[u]){ 41 int xx; 42 scc_cnt++;//注意scc_cnt也是从1开始的,因为要染色,区别于为染色的0 43 do{ 44 xx=stk[tot2--]; 45 vc[scc_cnt].push_back(xx); 46 col[xx]=scc_cnt; 47 vis[xx]=0; 48 }while(xx!=u); 49 } 50 } 51 void INIT() 52 { 53 for(int i = 0 ; i < maxn1 ; i++) 54 vc[i].clear(); 55 edge_cnt=0,tot1=0,tot2=0,scc_cnt=0,tot0=0; 56 memset(head,-1,sizeof(head)); 57 memset(stk,0,sizeof(stk)); 58 memset(in,0,sizeof(in)); 59 memset(out,0,sizeof(out)); 60 memset(dfn,0,sizeof(dfn)); 61 memset(low,0,sizeof(low)); 62 memset(col,0,sizeof(col)); 63 } 64 void suodian()//缩点 65 { 66 for(int i = 0 ; i < edge_cnt ; i++) 67 { 68 if(col[EDGE[i].from]!=col[EDGE[i].to]) 69 { 70 in[col[EDGE[i].to]]++;//缩点 71 out[col[EDGE[i].from]]++; 72 } 73 } 74 } 75 int main() 76 { 77 int n,m; 78 scanf("%d%d",&n,&m); 79 INIT(); 80 while(m--) 81 { 82 int a,b; 83 scanf("%d%d",&a,&b); 84 add(a,b); 85 } 86 for(int i = 1 ; i <= n; i++) 87 { 88 if(!dfn[i])Tarjan(i); 89 } 90 suodian(); 91 return 0; 92 } 93 /*4 5 94 1 3 95 2 4 96 4 2 97 1 4 98 2 1*/