L2-2 小字輩(搜尋/並查集)
阿新 • • 發佈:2022-03-28
題意
本題給定一個龐大家族的家譜,要請你給出最小一輩的名單。
輸入格式
輸入在第一行給出家族人口總數 N(不超過 100 000 的正整數) —— 簡單起見,我們把家族成員從 1 到 N 編號。隨後第二行給出 N 個編號,其中第 i 個編號對應第 i 位成員的父/母。家譜中輩分最高的老祖宗對應的父/母編號為 -1。一行中的數字間以空格分隔。
輸出格式
首先輸出最小的輩分(老祖宗的輩分為 1,以下逐級遞增)。然後在第二行按遞增順序輸出輩分最小的成員的編號。編號間以一個空格分隔,行首尾不得有多餘空格。
樣例1
input |
---|
9 2 6 5 5 -1 5 6 4 7 |
output |
---|
4 1 9 |
思路
這道題就是開vector二維陣列存父子關係,然後就搜唄。感覺深搜比廣搜直接。
具體做法都是先把每個爹的兒子們記錄下來,其中是-1的那個是老祖宗,我們從老祖宗開始往下搜。用maxd更新最大輩分。
第3種思路:用並查集存爹,然後邊打標記邊列舉每個兒子,分別遞迴找爹。
思路1(DFS)
#include <bits/stdc++.h> using namespace std; const int N = 5 + 1e5; vector<int> son[N]; // 下標是爹,值是兒子 int ans[N], root, maxd = 1, idx = 0; // root:老祖宗 maxd:最深深度 void dfs(int x, int d) { int n = son[x].size(); if (n == 0) { // 當前這個兒子沒有兒子了 if (maxd < d) { // 是否需要更新深度 maxd = d; idx = 0; // 深度更新了,前面存的都不算,抹掉 ans[idx++] = x; } else if (maxd == d) // 他的輩分等於當前已知的最小輩分,加入ans ans[idx++] = x; } else // 還有兒子 for (int i = 0; i < n; i++) dfs(son[x][i], d + 1); } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) { int t; scanf("%d", &t); if (t == -1) root = i; else son[t].push_back(i); } dfs(root, 1); if (maxd == 1) printf("1\n1\n"); else { printf("%d\n%d", maxd, ans[0]); for (int i = 1; i < idx; i++) printf(" %d", ans[i]); } return 0; }
思路2(BFS)
#include <bits/stdc++.h> using namespace std; const int N = 5 + 1e5; vector<int> son[N]; int depth[N]; int n, root; void bfs(int u) { queue<int> q; q.push(u); while (q.size()) { int x = q.front(); q.pop(); for (int i = 0; i < son[x].size(); i++) { if (!depth[son[x][i]]) { q.push(son[x][i]); depth[son[x][i]] = depth[x] + 1; } } } int maxd = -1; for (int i = 1; i <= n; i++) if (depth[i] > maxd) maxd = depth[i]; cout << maxd + 1 << '\n'; for (int i = 1, nf = 0; i <= n; i++) if (depth[i] == maxd) { if (nf++) cout << ' '; cout << i; } } int main() { cin >> n; for (int i = 1; i <= n; i++) { int t; scanf("%d", &t); if (t == -1) root = i; else son[t].push_back(i); } bfs(root); return 0; }
思路3(並查集)
#include <bits/stdc++.h>
using namespace std;
const int N = 5 + 1e5;
int fa[N]; // 存爹,順便用來求distance
int a[N]; // 存距離
int find(int x) {
if (a[x]) return a[x]; // 存過了就直接返回,就再存,否則tle
if (fa[x] == -1) return fa[x] = 1;
else return a[x] = find(fa[x]) + 1;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= n; i++) cin >> fa[i];
int maxd = 0;
for (int i = 1; i <= n; i++) {
int t;
t = get(i);
if (t > maxd) maxd = t;
}
cout << maxd << '\n';
for (int i = 1, nf = 0; i <= n; i++)
if (a[i] == maxd) {
if (nf++) cout << ' ';
cout << i;
}
}