強連通分量

翰林猿發表於2024-07-07
#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
	}
}

相關文章