题目描述:家谱树(信息学奥赛一本通-T1351)_Alex_McAvoy的博客-CSDN博客
概念部分为CSDN博主「独-」的原创文章,遵循CC 4.0 BY-SA版权协议,按要求附上原文链接:https://blog.csdn.net/qq_41713256/article/details/80805338
拓扑排序:在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。
算法概述:
- 先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
- 一直做改操作,直到所有的节点都被分离出来。
- 如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
下面是算法的演示过程:
开头所展示题目的代码实现:
#include <bits/stdc++.h>
using namespace std;
int tot, num, n, m;
// a[i][j]存点i的第j个后继点,c[i]存点i的出度,r[i]存点i的入度
int a[101][101], c[101], r[101];
// stack<int> s;
queue<int> s;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
int j;
cin >> j;
while (j != 0) {
// 数据初始化,看一下每个数组的作用应该能懂
c[i]++;
a[i][c[i]] = j;
r[j]++;
cin >> j;
}
}
for (int i = 1; i <= n; i++)
if (r[i] == 0) s.push(i); // 最开始就是入度为0的先入队
while (num < n) {
int temp = s.front(); // 队头元素开始处理
cout << temp << " ";
s.pop();
num++; // 统计已经完成排序的节点
for (int i = 1; i <= c[temp]; i++) {
// 从图中删除当前节点,所以该节点所有后继节点的入度-1
r[a[temp][i]]--;
// 如果减去后入度为0,则也入队
if (r[a[temp][i]] == 0) s.push(a[temp][i]);
}
}
return 0;
}