有向圖的連通性(判強連通)

cn是大帅哥886發表於2024-07-18

講義


Kosaraju


#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;

int n, m, u1, v1, vis[N], vis2[N], cnt=0;
vector<int> a[N], ra[N]; 
stack<int> st;
void dfs(int u)
{
	if (vis[u]) return ;
	vis[u]=1;
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		dfs(v);
	} 
	
	st.push(u);
}
void dfs2(int u)
{
	if (vis2[u]) return ;
	vis2[u]=cnt;
	
	for (int i=0; i<ra[u].size(); i++)
	{
		int v=ra[u][i];
		dfs2(v);
	}
}
void ko()
{
	for (int i=1; i<=n; i++) if (!vis[i]) dfs(i);
	
	while (!st.empty())
	{
		int u=st.top();
		st.pop();
		
		if (vis2[u]) continue;
		cnt++;
		dfs2(u);
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
		ra[v1].push_back(u1);
	}
	ko();
	
	printf("%d", cnt);
	return 0;
}

  

和上述步驟一樣,具體不多講了。

Tarjan


#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;

int n, m, u1, v1, dfn[N], low[N], idx=0, cnt=0, id[N];
stack<int> st;
vector<int> a[N];
void dfs(int u)
{
	dfn[u]=low[u]=++idx;
	st.push(u);
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if (!dfn[v])
		{
			dfs(v);
			low[u]=min(low[u], low[v]);
		}
		else if (!id[v]) low[u]=min(low[u], dfn[v]);
	} 
	
	if (low[u]==dfn[u])
	{
		cnt++;
		while (st.top()!=u)
		{
			id[st.top()]=cnt;
			st.pop();
		}
		id[st.top()]=cnt;
		st.pop();
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
	}
	
	for (int i=1; i<=n; i++)
		if (!dfn[i]) dfs(i);
	
	printf("%d", cnt);
	return 0;
}

  

有向圖的強連通分量和無向圖的點雙類似,當然只是類似,判斷條件一樣,應該可以感性理解一下

其餘都差不多了,就是沒有特判根節點

以上程式碼(板子)為第一題程式碼

第1題 SCC個數 檢視測評資料資訊

有一個n個點,m條邊的有向圖,請求出這個圖的強連通分量個數。

輸入格式

第一行為兩個整數n和m.

第二行至m+1行,每一行有兩個整數a和b,表示有一條從a到b的有向邊。

2≤n≤1e4,2≤m≤5×1e4,1≤a,b≤n。

輸出格式

僅一行,表示強連通分量個數。

輸入/輸出例子1

輸入:

5 4

2 4

3 5

1 2

4 1

輸出:

3

樣例解釋

第2題 SCC計數 檢視測評資料資訊

有一個n個點,m條邊的有向圖,請求出這個圖點數大於1的強連通分量個數。

輸入格式

第一行為兩個整數n和m.

第二行至m+1行,每一行有兩個整數a和b,表示有一條從a到b的有向邊。

2≤n≤1e4,2≤m≤5×1e4,1≤a,b≤n。

輸出格式

僅一行,表示點數大於1的強連通分量個數。

輸入/輸出例子1

輸入:

5 4

2 4

3 5

1 2

4 1

輸出:

1

樣例解釋

稍微加個判斷條件即可

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;

int n, m, u1, v1, vis[N], vis2[N], cnt=0, cnt2=0, ans=0;
vector<int> a[N], ra[N]; 
stack<int> st;
void dfs(int u)
{
	if (vis[u]) return ;
	vis[u]=1;
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		dfs(v);
	} 
	
	st.push(u);
}
void dfs2(int u)
{
	if (vis2[u]) return ;
	vis2[u]=cnt;
	cnt2++;
	
	for (int i=0; i<ra[u].size(); i++)
	{
		int v=ra[u][i];
		dfs2(v);
	}
}
void ko()
{
	for (int i=1; i<=n; i++) if (!vis[i]) dfs(i);
	
	while (!st.empty())
	{
		int u=st.top();
		st.pop();
		
		if (vis2[u]) continue;
		cnt2=0, cnt++;
		
		dfs2(u);
		
		if (cnt2>1) ans++;
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
		ra[v1].push_back(u1);
	}
	ko();
	
	printf("%d", ans);
	return 0;
}

  

個人推薦用taijan演算法,ko演算法常數過大

相關文章