图和树(下)拓扑排序、强连通分量

本文详细介绍了拓扑排序的概念及其Kahn算法实现,同时讲解了强连通分量的检测方法,包括Kosaraju算法。通过两遍深度优先搜索,可以有效地找出图中的强连通分量。最后,还提到了如何将强连通分量进行缩点操作,简化图的结构。这些算法在图论和有向图分析中具有重要应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拓扑排序

还有给定一个 DAG,如果从 u 到 v 有边,则认为 v 依赖于 u 。如果 u 到 v 有路径( u 可达 v ),则称 v 间接依赖于 u 。

拓扑排序的目标是将所有节点排序,使得排在前面的节点不能依赖于排在后面的节点。

Kahn算法

bool toposort(){
	q = new queue();
	for(int i =0;i < n;i++)
		if(in_deg[i] == 0 ) q.push(i);
	ans = new vector();
	while(! q.empty())
	{
		u = q.pop();
		ans.push_back();
		for each edge(u,v){
			if(--in_deg[v] == 0) q.push(v);
		}
	}
	if(ans.size() == n){
		for(int i = 0;i < n;i++)
		cout << ans[i] << endl;
		return true;
	} else {
		return false;
	}
}

强连通分量

强连通分量的例子
第一遍 dfs 确定原图的逆后序序列,即 4 7 6 5 1 2 3 8
• 第二遍 dfs 在反图中按照逆后序序列进行遍历
• 反图即将原图中的有向边反向
• 每次由起点遍历到的点即构成一个 SCC

Kosaraju 代码

void dfs1(int x){
	vis[x] = 1;
	for(auto y:G1[x])
		if(!vis[y]) difs1(y);
	dfn[++dcnt] = x;//确定后序
}
void dfs2(int x){
	c[x] = scnt;//赋值来连通分量的标号
	for(auto y:G2[x])
		if(!c[y]) dfs2(y);
}void kosaraju(){
	dcnt = scnt  =0;
	memset(c,0,sizeof(c));
	memset(vis,0,sizeof(vis));
for(int i=1;i <= n;i++)
	if(!vis[i]) dfs1(i);
for(int i = n;i >= 1;i--)//按照逆后序的顺序遍历
	if(!c[dfn[i]]) 
	{
	 ++scnt;
	 dfs2(dfn[i]);
	}
}

将强连通分量缩点

void shrinkPoints()
{
   for(int i = 1;i<=n;i++)
    for(auto y:G1[i])//遍历图中的每一条边
    {
        if(c[i] == c[y])
        continue;//属于同一个连通分量
        int u = c[i];
        int v = c[y];
        G3[u].push_back(v);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值