有向图的连通性(判强连通)

讲义


 

 

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算法常数过大

 

有向图缩点后一定是有向无环图

 

posted @ 2024-07-18 08:10  cn是大帅哥886  阅读(56)  评论(0)    收藏  举报