欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

tarjan算法求解强连通分量

程序员文章站 2023-12-23 00:02:16
...

强连通分量是有向图中的概念。

在有向图中,若任意两个顶点都是连通的,那么就是强连通图,非强连通图中的强连通子图称为强连通分量。

可以用tarjan算法求解,任选一个节点作为dfs树的根节点,注意到对于节点u,若子树中的任意节点无回边到节点u的祖先(但是回到u),则子树以及u节点为一个强连通分量,也就是能通过u访问u子树的任意一个节点,但是没有任意一个节点可以返回u节点。当然该子树。

对于图1这种情况,存在从v到u的回边,那么必然在u。v构成的子图中任意节点都能回到u。

图2这种情况的话,x没有一条回到其祖先节点的回边,所以x自己构成一个强连通分量,然后剩下来的u a v构成一个强连通分量

使用low[u]表示节点u以及u的子节点回边到的祖先节点。dfsn[u]表示节点u的dfs序号。初始low[u]=dfsn[u]。如果u的子树访问完成后没有更新low[u],那么可以肯定没有回边到节点u的祖先节点。如果有节点回边到节点u,那么连同u的子树构成一个连通分量。

tarjan算法求解强连通分量

#include <cstdio>
#include <algorithm>
#include <stack>
using namespace std;
const int MAXN=10;
struct Edge{
	int to,next;
	Edge(){}
	Edge(int a,int b):to(a),next(b){}
};
int node[MAXN],cnt,dfsn[MAXN],low[MAXN],c;
bool vis[MAXN];
Edge edge[MAXN*2];
stack<int> st;
bool inStack[MAXN];
void addEdge(int from,int to){
	edge[cnt].to=to;
	edge[cnt].next=node[from];
	node[from]=cnt++;
}
void tarjan(int from){
	vis[from]=true;
	low[from]=dfsn[from]=c++;
	inStack[from]=true;
	st.push(from);
	for(int i=node[from];i+1;i=edge[i].next){
		int to=edge[i].to;
		if(!vis[to]){
			tarjan(to);
			low[from]=min(low[from],low[to]);
		}else if(inStack[to]&&dfsn[to]<low[from]){
			low[from]=dfsn[to];
		}//存在回边到u的祖先
	}
	if(dfsn[from]==low[from]){//如果u的子节点有回到u祖先的回边,那么都不会相等
		int x;
		do{
			x=st.top();
			st.pop();
			inStack[x]=false;
			printf("%d ",x);
		}while(x!=from);
		printf("\n");
	}
}
int main(){
	freopen("./in.txt","r",stdin);
	int n,m,u,v;
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(vis,false,sizeof(vis));
		memset(dfsn,-1,sizeof(dfsn));
		memset(low,-1,sizeof(-1));
		memset(node,-1,sizeof(node));
		memset(inStack,false,sizeof(inStack));
		while(!st.empty()){
			st.pop();
		}
		c=cnt=0;
		for(int i=0;i<m;i++){
			scanf("%d%d",&u,&v);
			addEdge(u,v);
		}
		tarjan(0);
	}
	return 0;
}

in.txt

5 6
0 1
1 2
2 3
2 4
3 1
4 1


上一篇:

下一篇: