Kosaraju算法

今天学了Kosaraju算法!曼波

模板:p2863
对于一个图怎么求它有多少个强连通分量呢?!

1,什么是强连通分量?

• 强连通:在一个有向图G中,如果两个顶点u、v间存在
一条u到v的路径且也存在一条v到u的路径,则称这两个
顶点u、v是强连通的
• 强连通图:有向图G的任意两个顶点都强连通,则称G是
一个强连通图
• 极大强连通子图:G是一个极大强连通子图,当且仅当G
是一个强连通子图且不存在另一个强连图子图G’ G
• 强连通分量:有向非强连通图的极大强连通子图,称为
强连通分量;

Kosaraju算法

一种使用两次dfs的求解方法!一次在原图上,一次在反图上;
然后我们在第一次dfs时记录所有结点的退出顺序,并且在第二次在反图上dfs时按照退出顺序的逆序遍历;
这样第二次就是拓扑序从小到大做,每次就能恰好得到一个强连通分量;
代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
int t=0,ans=0;
vector<int> g[100005];
vector<int> gp[100005];//存反图
int b[50005],s[50005];
void dfs1(int x){
	b[x]=1;
	for(int i=0;i<g[x].size();i++){
		if(!b[g[x][i]]) dfs1(g[x][i]); 
	}
	s[++t]=x;//记录退出顺序
	return;
}
void dfs2(int x){
	b[x]=1;
	for(int i=0;i<gp[x].size();i++){
		if(!b[gp[x][i]]){
			cnt++;
			dfs2(gp[x][i]);	
		}
	}
	return;
}
int main(){
	memset(g,0,sizeof(g));
	memset(gp,0,sizeof(gp));
	cin>>n>>m;
	int x,y;
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		g[x].push_back(y);
		gp[y].push_back(x);
	}
	for(int i=1;i<=n;i++){//第一次dfs
		if(!b[i]) dfs1(i);
	}
	memset(b,0,sizeof(b));
	for(int i=t;i>=1;i--){//第二次dfs
		cnt=0;
		if(!b[s[i]]){
			dfs2(s[i]);
			if(cnt>0) ans++;//题目要求判断点数大于一
		} 
	}
	cout<<ans;
	return 0;
}

听说tarjan更好呢...题解也全是tarjan
下次再学吧~

posted @ 2025-09-30 21:53  Turkey_VII  阅读(10)  评论(0)    收藏  举报