【算法-图论基础】拓扑排序(深度优先搜索实现)

拓扑排序,其实就是根据一定的优先级信息,将信息在图这种抽象出来的数据结构中集成,最后生成的顺序。


下面来看一道模板题,来自洛谷的B3644。

B3644 【模板】拓扑排序 / 家谱树

拓扑排序是dfs和bfs在图上的经典应用,本文以笔记的形式,通过bfs来实现拓扑排序。

在实现拓扑排序之前,我们需要知道几个概念,即图节点的入度和出度。

如上图,节点1的入度为3,出度为0,节点2的入度为0,出度为2,,很显然,在有向图中,入度为零的节点优先级最高,排在最首,出度为0的节点优先级最低,排在最尾(2>1),方向是从优先级高指向优先级低(或者反过来也可以),当然,如果将所给的信息放在有向图中后,发现出现了环,那么不存在优先级最高(最低)的节点,也就不能进行排序,也就是说,拓扑排序只能在有向无环图中进行。(如下图)

使用bfs实现拓扑排序,可以从入度考虑,也可以从出度考虑,分别对应两种原理:

1、无前驱的节点优先。入度为零的节点优先级最高,记录,删除其与相邻节点的边,再找入度为零的节点(它在剩下的节点中优先级最高),记录,直到找完所有节点,如果遇到多个入度为零的节点,则它们之间的顺序不确定,造成了拓扑排序的不确定性(多解)。

2、无后继的节点优先。按出度思考同理,每次找优先级最低的节点。

有没有感觉到这其实类似于选择排序(堆排序)的思想?


下面是C/C++代码实现:

#include<bits/stdc++.h> 
using namespace std;
const int N=2e3+10;
//#define int long long
//基于广度优先搜索实现的拓扑排序
int n,h[N],ans[N],k;
queue<int> q;
struct edge
{
	int from,to;
	edge(int a,int b){from=a;to=b;}
};
vector<edge> a[N]; // 邻接表存图 
void init()
{
	for(int i=1;i<=n;i++) a[i].clear();
	return;
}
signed main()
{
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;i++)
    {
		int re;
		while((scanf("%d",&re),re))
		{
			a[i].push_back(edge(i,re));
			h[re]++; // 保存入度 
		}
	} // 读入图
	for(int i=1;i<=n;i++) if(!h[i]) q.push(i);
	while(!q.empty())
	{
		int b=q.front();
		q.pop();
		ans[k++]=b;
		for(int i=0;i<(int)a[b].size();i++) //遍历所有邻居 
		{
			h[a[b][i].to]--; //邻居入度减一 
			if(!h[a[b][i].to]) q.push(a[b][i].to); // 入度减为零的入队 
		}
	}
	for(int i=0;i<k;i++) printf("%d ",ans[i]);
	return 0;
}

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值