拓扑排序模板题

https://www.luogu.com.cn/problem/B3644

有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。给出每个人的后代的信息。输出一个序列,使得每个人的后辈都比那个人后列出。

输入格式
\(1\) 行一个整数 \(N(1 \le N \le 100)\),表示家族的人数。接下来 \(N\) 行,第 \(i\) 行描述第 \(i\) 个人的后代编号 \(a_{i,j}\),表示\(a_{i,j}\)\(i\) 的后代。每行最后是 \(0\) 表示描述完毕。

输出格式
输出一个序列,使得每个人的后辈都比那个人后列出。如果有多种不同的序列,输出任意一种即可。

输入
5
0
4 5 1 0
1 0
5 3 0
3 0
输出
2 4 5 3 1

拓扑排序是一个有向无环图的所有顶点的线性序列。
该序列需要满足每个顶点出现且只出现一次和如果有一条 \(A\)\(B\) 的路径,在序列中 \(A\) 出现在 \(B\) 的前面。
这道题目显然全部满足以上条件。如果不懂可以看下面样例的有向无环图。
image
拓扑排序的步骤:

  • 计算每个点的入度。
  • 入度为 0 就加入队列。
  • 当队列不为空则循环:
  • 取出队首元素并输出。
  • 遍历队首元素的连边,对应节点的入度 -1。
  • 当对应的节点入度为 0 就加入队列。

我们看样例的图,其中 1 到 5 的入度分别为 2,0,2,1 和 2。我们就把 2 号节点加入队列。队首现在不为空,所以我们取出 2 号节点,并且输出出来。这时候因为他没有祖先所以一定是现在辈分最大的所以输出出来。删除所有对应节点的入度之后我们会发现 4 号节点入度为 0。所以加入队列。然后取出队首 4 号节点并且输出。很明显他的祖先 2 号节点已经没了,所以 4 号节点已经没有辈分比他还大的了。按照上面的步骤我们就可以完成此道题目了。

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1e6+100;
vector<int>e[maxn];
int in[maxn];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		while(cin>>x&&x){
			e[i].push_back(x);
			in[x]++;
		}
	}
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(in[i]==0)
			q.push(i);
	}
	while(!q.empty()){
		int t=q.front();
		q.pop();
		cout<<t<<" ";
		for(int i=0;i<e[t].size();i++){
			in[e[t][i]]--;
			if(in[e[t][i]]==0){
				q.push(e[t][i]);
			}
		}
	}
}
posted @ 2024-05-29 10:17  lipu123  阅读(64)  评论(0)    收藏  举报