来一道裸代码。
输入:
一个图有向图。
输出:
它每个强连通分量。
这个图就是刚才讲的那个图。一模一样。
input:
6 8
1 3
1 2
2 4
3 4
3 5
4 6
4 1
5 6
output:
6
5
3 4 2 1
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<algorithm> #include<map> #define maxn 200005 using namespace std; struct node { int v,next; //v表示指向的点 next表示 }mp[1005]; int DFN[1005],LOW[1005]; //DFN[]作为这个点搜索的次序编号(时间戳) //LOW[]作为每个点在这颗树中的,最小的子树的根,每次保证最小,like它的父亲结点的时间戳这种感觉 int stack[1005],heads[1005],visit[1005],cnt,tot,index; // 栈 访问顺序 是否访问 void add(int x,int y) { mp[++cnt].next=heads[x]; mp[cnt].v=y; heads[x]=cnt; return ; } void tarjan(int x) { DFN[x]=LOW[x]=++tot; //初始化x stack[++index]=x; //进栈 visit[x]=1; //表示x已经入栈 for(int i=heads[x];i!=-1;i=mp[i].next){ if(!DFN[mp[i].v]) //如果没有被访问 { tarjan(mp[i].v); //往下延伸就是递归 LOW[x]=min(LOW[x],LOW[mp[i].v]); //递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情 } else if(visit[mp[i].v]) //如果访问过,并还在栈里 { LOW[x]=min(LOW[x],DFN[mp[i].v]); //比较谁是谁的儿子/父亲。就是链接对应关系 } } if(LOW[x]==DFN[x]){ //发现整个连通分量子树里的最小根 while(1) { cout<<stack[index]<<" "; visit[stack[index]]=0; index--; if(x==stack[index+1]) break; //出栈,并且输出 } cout<<endl; } } int main() { memset(heads,-1,sizeof(heads)); int n,m; cin>>n>>m; int x,y; for(int i=1;i<=m;i++) { cin>>x>>y; add(x,y); } for(int i=1;i<=n;i++) { if(!DFN[i])tarjan(i); //当这个点没有访问过,就从这个点开始,防止图没有走完 } return 0; }
还有各大理解网站: (杂着看,就可以看懂)
http://blog.miskcoo.com/2016/07/tarjan-algorithm-strongly-connected-components
https://blog.csdn.net/mengxiang000000/article/details/51672725
https://www.cnblogs.com/yxysuanfa/p/7396057.html
原文地址:https://www.cnblogs.com/huangzzz/p/8922029.html
时间: 2024-11-14 13:25:56