图论总结(4)有向图的强连通分量

有向图的强连通分量:有向图G中,如果有两个顶点间至少存在一条路径,称两个顶点强连通(stringly connected),简称SCC。

如果有向图G的每个顶点都强连通,则称G是一个强连通图。

非强连通图的极大强连通子图,称为强连通分量。

蓝书上给了两种算法:

一.Kosaraju算法:

按照SCC图拓扑排序的逆序进行遍历。先正序遍历的到拓扑排序,再构造G的反向图G2(所有边相反),最后按拓扑排序的逆序进行遍历。

模板:

vector<int>G[maxn],G2[maxn];
vector<int>s;
int vis[maxn],sccno[maxn],scc_cnt;
void dfs1(int u){
	if(vis[u])return ;
	vis[u]=1;
	for(int i=0;i<G[u].size();i++)dfs1(G[u][i]);
	s.push_back(u);
}
void dfs2(int u){
	if(sccno[u])return ;
	sccno[u]=scc_cnt;
	for(int i=0;i<G2[u].size();i++)dfs2(G[u][i]);
}
void find_scc(int n){
	scc_cnt=0;
	s.clear();
	memset(sccno,0,sizeof(sccno));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)if(!vis[i])dfs1;
	for(int i=n-1;i>=0;i--)if(!sccno[s[i]]){
		scc_cnt++;dfs2[s[i]];
	}
}

二.tarjan算法:
定义pre(u)数组为节点u的次序编号(时间戳)。low(u)为u或u的子树能够追溯到的最早节点的次序号。
由定义可以得出:
low(u)=min(pre(v),low(u))v为u的子树且v!=fa;
当DFN(u)=low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
模板:
vector<int>G[maxn];
int pre[maxn],low[maxn],sccno[maxn];
int dfs_clock,scc_cnt;
stack<int>s;
void dfs(int u){
	pre[u]=low[u]=++dfs_clock;
	s.push(u);
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(!pre[v]){
			dfs(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!sccno[v]){
			low[u]=min(low[u],pre[v]);
		}
		if(low[u]==pre[u]){
			scc_cnt++;
			for(;;){
				int x=s.top();s.pop();
				sccno[x]=scc_cnt;
				if(x==u)break;
			}
		}
	}
}
void find_scc(int n){
	dfs_clock=scc_cnt=0;
	memset(sccno,0,sizeof(sccno));
	memest(pre,0,sizeof(pre));
	for(int i=0;i<n;i++)
	if(!pre[i])dfs(i);
}
个人觉得第一种要好写一点。
要开学了,感觉图论总结了就没时间复习其他了,之后总结就精简点了。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值