强连通分量

#include<bits/stdc++.h>
using namespace std;

int n; // 节点数量
int G[1010][1010]; // 图的邻接矩阵表示
int Time,sum; // Time用于记录DFS的时间,sum用于记录强连通分量的数量
int beg[1010],low[1010]; // beg记录每个节点开始被访问的时间,low记录每个节点能够回溯到的最早的节点的时间
stack<int> S;  // 用于DFS的栈
int in_stack[1010];  // 记录每个节点是否在栈中
void DFS(int v); // 深度优先搜索函数

int main(){
	int a,b,m; // a和b用于读取边的两个节点,m用于读取边的数量
	while(scanf("%d",&n)!=EOF){ // 读取节点数量
		scanf("%d",&m); // 读取边的数量
		memset(G,0,sizeof(G)); // 初始化图的邻接矩阵
		for(int i=1;i<=m;i++){ // 读取所有的边
			scanf("%d%d",&a,&b);
			G[a][b]=1; // 在邻接矩阵中添加边
		}
		Time=sum=0; // 初始化时间和强连通分量数量
		memset(beg,0,sizeof(beg)); // 初始化每个节点的开始访问时间
		memset(low,0,sizeof(low)); // 初始化每个节点的最早可达节点的时间
		memset(in_stack,0,sizeof(in_stack)); // 初始化每个节点是否在栈中的标记
		for(int z=1;z<=n;z++){ // 对每个节点进行深度优先搜索
			if(beg[z]==0){
				DFS(z);
			}
		}
		printf("%d\n",sum); // 输出强连通分量的数量
	}
	return 0;
}

void DFS(int v){  // 深度优先搜索函数
	beg[v]=low[v]=++Time; // 初始化每个节点的开始访问时间和最早可达节点的时间
	S.push(v); // 将节点放入栈中
	in_stack[v]=1; // 标记节点在栈中
	
	for(int i=1;i<=n;i++){ // 遍历所有节点
		if(G[v][i]==1){ // 如果存在从v到i的边
			
			if(beg[i]==0){ // 如果节点i还没有被访问过
				DFS(i); // 对节点i进行深度优先搜索
				low[v]=min(low[v],low[i]); // 更新节点v的最早可达节点的时间
			}else if(in_stack[i]==1){ // 如果节点i在栈中
				low[v]=min(low[v],low[i]); // 更新节点v的最早可达节点的时间
			}
		}
	}
	if(beg[v]==low[v]){ // 如果节点v是一个强连通分量的根节点
		int t;
		sum++; // 强连通分量数量加1
		do{
			t=S.top(); // 取出栈顶元素
			S.pop(); // 弹出栈顶元素
			in_stack[t]=0; // 标记节点t已经不在栈中
		}while(t!=v); // 直到弹出的是节点v
	}
}

posted @ 2024-07-07 10:25  翰林猿  阅读(6)  评论(0编辑  收藏  举报