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

题目传送门

题意

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

分析

拓扑排列是一个有向无环图的所有顶点的线性序列。

该序列需要满足以下条件:

  • 每个顶点出现且只出现一次。
  • 如果图中有一条 \(A\)\(B\) 的路径,在序列中 \(A\) 出现在 \(B\) 的前面。

拓扑排序的步骤:

计算每个点的入度
入度为 0 则加入队列
while 队列非空:
	取出队首元素并输出。
	遍历队首元素的出边,对应结点的入度 -1
	if 对应结点的入度 = 0:
		将该结点加入队列

代码

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
int to[N], nxt[N], head[N], in[N], out[N], n, u, v, cnt;

inline void add_edge(int u, int v){ // 加边函数
	to[++cnt] = v;
	nxt[cnt] = head[u];
	head[u] = cnt;
}

inline void topo(){
	queue<int> q;
	for(int i = 1; i <= n; i++)
		if(!in[i]) cout << i << ' ', q.push(i); // 判断入度是否为 0,即是否可以放入队列
	while(!q.empty()){
		u = q.front(); q.pop(); // 取出队首元素
		for(int i = head[u]; ~i; i = nxt[i]){ // 遍历所有出边
			v = to[i], in[v]--;
			if(!in[v]){
				cout << v << ' ';
				q.push(v);
			}
		}
	}
}

int main(){
	ios::sync_with_stdio(false);
	memset(head, -1, sizeof head);
	cin >> n;
	for(int i = 1; i <= n; i++){
		int x;
		while(cin >> x){
			if(!x) break;
			add_edge(i, x);
			in[x]++, out[i]++;
		}
	}
	topo();
	return 0;
}
posted @ 2023-06-24 13:49  心灵震荡  阅读(581)  评论(2)    收藏  举报