AcWing 1191. 家谱树

\(\color{black}Acwing 1191.家谱树\)

题意转化

给出一个有 \(n\) 个节点的有向图,输出一个序列,使得序列中任意父节点都排在子节点前


题目分析

拓扑排序模板题,进行排序后输出即可。


拓扑排序

给出一个 \(DAG\) (有向无环图),如果从节点 \(u\)\(v\) 有边,那么认为 \(v\) 依赖于 \(u\), 如果从节点 \(u\)\(v\) 有简单路径,那么认为 \(v\) 间接依赖于 \(u\), 而拓扑排序的目标即是将所有结点排序,使得排在前面的节点不能依赖于排在后面的节点,我们称此序列为 拓扑序列


下面给出拓扑排序的步骤。

\(1.\) 选择图中一个入度为 \(0\) 的点
\(2.\) 输出此顶点,并删除此节点及该节点的所有出边


下边给出拓扑排序的一个例子。

选择点 \(1\), 输出并删除此节点及该节点的所有出边。

选择点 \(2\), 输出并删除此节点及该节点的所有出边。

选择点 \(3\), 输出并删除此节点及该节点的所有出边。

选择点 \(4\), 输出并删除此节点及该节点的所有出边。

至此,拓扑排序结束。

个人代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e2 + 5;
#define ll long long
int a[N];
int in[N]; // 存储每一个点的入度
vector <int> G[N];
int n;
void toposort()
{
	vector <int> ans; // 存储答案
	queue <int> q; // 存储入度为 0 的点
	for(int i = 1; i <= n; i++)
	{
		if(in[i] == 0)
		{
			q.push(i);
		}
	}
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		ans.push_back(u);
		for(auto x : G[u]) // 将与点 u 相邻的点入度减一
		{
			if(in[x] > 0)
			{
				in[x]--;
				if(in[x] == 0) 
				{
					q.push(x);
				}
			}
		}
	}
	for(auto i : ans)
	{
		cout << i << ' ';
	}
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		while(1)
		{
			int v;
			cin >> v;
			if(v == 0)
			{
				break;
			}
			G[i].push_back(v);
			in[v]++;
		}
	}
	toposort();
	return 0;
}
posted @ 2026-06-09 14:18  ly_fish  阅读(9)  评论(0)    收藏  举报