B3644 【模板】拓扑排序 / 家谱树 题解
【模板】拓扑排序 / 家谱树
题目描述
有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。给出每个人的后代的信息。输出一个序列,使得每个人的后辈都比那个人后列出。
输入格式
第 111 行一个整数 NNN(1≤N≤1001 \le N \le 1001≤N≤100),表示家族的人数。接下来 NNN 行,第 iii 行描述第 iii 个人的后代编号 ai,ja_{i,j}ai,j,表示 ai,ja_{i,j}ai,j 是 iii 的后代。每行最后是 000 表示描述完毕。
输出格式
输出一个序列,使得每个人的后辈都比那个人后列出。如果有多种不同的序列,输出任意一种即可。
样例 #1
样例输入 #1
5
0
4 5 1 0
1 0
5 3 0
3 0
样例输出 #1
2 4 5 3 1
拓扑排序的模板题。
拓扑排序是一个有向无环图的所有顶点的线性序列。
该序列需要满足每个顶点出现且只出现一次和如果有一条 AAA 到 BBB 的路径,在序列中 AAA 出现在 BBB 的前面。
这道题目显然全部满足以上条件。如果不懂可以看下面样例的有向无环图。

拓扑排序的步骤:
-
计算每个点的入度。
-
入度为 000 就加入队列。
-
当队列不为空则循环:
-
取出队首元素并输出。
-
遍历队首元素的连边,对应节点的入度 −1-1−1。
-
当对应的节点入度为 000 就加入队列。
-
我们看样例的图,其中 111 到 555 的入度分别为 222,000,222,111 和 222。我们就把 222 号节点加入队列。队首现在不为空,所以我们取出 222 号节点,并且输出出来。这时候因为他没有祖先所以一定是现在辈分最大的所以输出出来。删除所有对应节点的入度之后我们会发现 444 号节点入度为 000。所以加入队列。然后取出队首 444 号节点并且输出。很明显他的祖先 222 号节点已经没了,所以 444 号节点已经没有辈分比他还大的了。按照上面的步骤我们就可以完成此道题目了。
#include<bits/stdc++.h>
#define For(i,a,b) for(i=a;i<=b;i++)
#define FOR(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int N = 5e5 + 10;
int n;
vector<int> p[N];
void add(int u, int v) {
p[u].push_back(v);
}
bool vis[N];
stack<int> ans;
void dfs(int x) {
for (auto u : p[x]) {
if (vis[u]) continue;
dfs(u);
}
vis[x] = 1;
ans.push(x);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int i;
cin >> n;
For(i, 1, n) {
int x;
while (cin >> x && x) {
add(i, x);
}
}
For(i, 1, n) {
if (!vis[i])
dfs(i);
}
while (ans.size()) {
cout << ans.top() << ' ';
ans.pop();
}
}
更多推荐



所有评论(0)