拓扑排序简介

1 简介

先来一道题: 家谱树
如果画出这张图, 会发现它是没有环的, 这也是拓扑排序适用的DAG(有向无环图)
在这道题中, 每个人想要输出, 就要先输出他的父亲, 按照这个规律输出的序列叫做拓扑序列, 可以看出一张图的拓扑序列是不唯一的, 我们可以把入度为 0 0 0的点视作起点

2 分类

拓扑排序可以分成 b f s bfs bfs形式和 d f s dfs dfs形式

2.1 bfs形式

步骤如下:

  1. 建立一个队列和一个统计入度
  2. 将入度为 0 0 0的点入队
  3. 取出队首元素并输出
  4. 删除此点为起点所有的连边
  5. 将入度为 0 0 0的点入队
  6. 如果队列不为空重复 3 − 5 3-5 35

如果输出的点数与图中顶点数相同说明图中所有节点已经被遍历过了, 时间复杂度是 O ( N + E ) O(N+E) O(N+E)
如果没有, 说明图中存在环

2.2 dfs形式

步骤如下:

  1. 建立 v i s vis vis数组统计点是否被遍历到, 一个记录序列的列表 t o p o topo topo
  2. 遍历所有点, 如果没有遍历过且此点入度为 0 0 0, 从此点开始 d f s dfs dfs
  3. d f s dfs dfs遍历每一个点可以连接到的点, 如果此点没有被遍历到
  4. 按照返回的顺序把点加入 t o p o topo topo数组, v i s i = 1 vis_i = 1 visi=1
  5. 最后倒叙数出 t o p o topo topo数组

3 家谱树AC代码

#include <iostream>
#include <cstdio>
#include <queue> 
#include <vector>
using namespace std;

const int N = 105;
int n, du[N];
vector<vector<int> > g(N);
priority_queue<int, vector<int>, greater<int> > q;
int main(){
	scanf("%d", &n);
	for(int i = 1;i <= n;i++){
		int x;
		while(~scanf("%d", &x) && x != 0){
			du[x]++;
			g[i].push_back(x);
		}
	}
	for(int i = 1;i <= n;i++)
		if(du[i] == 0)
			q.push(i);
	while(!q.empty()){
		int x = q.top();
		q.pop();
		printf("%d ", x);
		for(int i = 0;i < g[x].size();i++){
			int y = g[x][i];
			du[y]--;
			if(du[y] == 0)	q.push(y);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值