1. 问题描述:
有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。给出每个人的孩子的信息。输出一个序列,使得每个人的孩子都比那个人后列出。
输入格式
第 1 行一个整数 n,表示家族的人数;接下来 n 行,第 i 行描述第 i 个人的孩子;每行最后是 0 表示描述完毕。每个人的编号从 1 到 n。
输出格式
输出一个序列,使得每个人的孩子都比那个人后列出;数据保证一定有解,如果有多解输出任意一解。
数据范围
1 ≤ n ≤ 100
输入样例:
5
0
4 5 1 0
1 0
5 3 0
3 0
输出样例:
2 4 5 3 1
来源:https://www.acwing.com/problem/content/1193/
2. 思路分析:
分析题目可以知道我们可以将每一个人看成是一个节点,本质上求解的是拓扑排序的序列,拓扑排序是对于有向图来说的,使得每一条边都是前面的节点指向后面的节点,当存在环的时候是没有拓扑排序的,如果一个有向图可以拓扑排序那么这个图称为拓扑图,拓扑图等价于有向无环图。算法流程:
- 遍历每一条边的时候统计节点的入度;
- 将所有入度为0的点入队,当队列非空的时候执行循环,弹出队头元素,遍历队头元素的所有出边,将出边对应的节点的入度减1,如果发现度数为0之后那么将其加入到队列中,并且所有度数为0的节点都是拓扑排序的序列。
3. 代码如下:
import collections
from typing import List
class Solution:
def topsort(self, n: int, d: List[int], g: List[List[int]], res: List[int]):
q = collections.deque()
for i in range(1, n + 1):
# 将入度为0的点入队
if d[i] == 0:
q.append(i)
res.append(i)
while q:
# 弹出队首节点
p = q.popleft()
# 遍历p的所有邻接点
for next in g[p]:
# 对应的入度减1
d[next] -= 1
# 入度为0之后将当前节点加入到队列中
if d[next] == 0:
q.append(next)
# 拓扑排序的序列中加入当前的节点next
res.append(next)
def process(self):
n = int(input())
# 邻接表
g = [list() for i in range(n + 10)]
d = [0] * (n + 10)
for i in range(1, n + 1):
s = input()
# 当len(s) == 1的时候说明没有孩子
if len(s) > 1:
s = s.split()
for j in range(len(s) - 1):
t = int(s[j])
g[i].append(t)
d[t] += 1
res = list()
# 拓扑排序
self.topsort(n, d, g, res)
for x in res:
print(x, end=" ")
if __name__ == "__main__":
Solution().process()