##[$AcWing$ $1191$. 家谱树](https://www.acwing.com/problem/content/1193/) ### 一、题目描述 有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。 给出每个人的孩子的信息。 输出一个序列,使得每个人的孩子都比那个人后列出。 **输入格式** 第 $1$ 行一个整数 $n$,表示家族的人数; 接下来 $n$ 行,第$i$ 行描述第 $i$ 个人的孩子; 每行最后是 $0$ 表示描述完毕。 每个人的编号从 $1$ 到 $n$。 **输出格式** 输出一个序列,使得每个人的孩子都比那个人后列出; 数据保证一定有解,如果有多解输出任意一解。 **数据范围** $1≤n≤100$ **输入样例**: ```cpp {.line-numbers} 5 0 4 5 1 0 1 0 5 3 0 3 0 ``` **输出样例**: ```cpp {.line-numbers} 2 4 5 3 1 ``` ### 二、知识铺垫 [前导知识](https://www.cnblogs.com/littlehb/p/16935872.html) ### 三、实现代码 ```cpp {.line-numbers} #include using namespace std; const int N = 110, M = N * N; int n; int din[N]; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } vector path; // 求拓扑序的模板 /* ① 所有入度为0的点入队列 ② 队头元素出队,遍历它相临的点,并且将相临的点入度-1 ③ 如果减1后的入度为0,则此点入队列,意味着它的前序依赖已完成 */ void topsort() { queue q; // 所有入度为0的入队列 for (int i = 1; i <= n; i++) if (din[i] == 0) q.push(i); while (q.size()) { int u = q.front(); q.pop(); path.push_back(u); for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; din[v]--; if (din[v] == 0) q.push(v); } } } int main() { memset(h, -1, sizeof h); scanf("%d", &n); for (int a = 1; a <= n; a++) { int b; while (scanf("%d", &b), b) { // b==0时结束读入 add(a, b); din[b]++; // 入度++ } } // 拓扑序 topsort(); // 输出任意一组拓扑序 for (int i = 0; i < n; i++) printf("%d ", path[i]); return 0; } ``` ### 四、如果要求输出由小到大的字典序 ```cpp {.line-numbers} #include using namespace std; const int N = 110, M = N * N; int n; int din[N]; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } vector path; // 如果要按字典序输出拓扑序,那么使用小顶堆即可 void topsort() { priority_queue, greater> q; // 所有入度为0的入队列 for (int i = 1; i <= n; i++) if (din[i] == 0) q.push(i); while (q.size()) { int u = q.top(); q.pop(); path.push_back(u); for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; din[v]--; if (din[v] == 0) q.push(v); } } } int main() { memset(h, -1, sizeof h); cin >> n; for (int a = 1; a <= n; a++) { int b; while (cin >> b, b) { add(a, b); din[b]++; // 入度++ } } // 拓扑序 topsort(); // 输出任意一组拓扑序 for (int i = 0; i < n; i++) printf("%d ", path[i]); return 0; } ```