题解:luogu P2018 消息传递
题目链接:https://www.luogu.com.cn/problem/P2018
数据范围 \(N\leq 1000\),很容易想到 \(O(N)\) 枚举根,\(O(N)\) 树形 dp。
设 \(f_{i}\) 表示在以 \(i\) 为根的子树中传布消息所需要的时间。
考虑转移,不难想到贪心优先传递耗时大的子树,\(k\) 表示 \(i\) 的儿子 \(j\) 按 \(f_j\) 降序排列后的下标,所以转移方程
\[f_i=\max_{j\in\text{son}_{i}}\{f_j+k\}
\]
以 \(u\) 为根的答案是 \(f_u+1\),因为 \(u\) 得知消息也需要 \(1\) 的代价。时间复杂度 \(O(N^2\log N)\)。
#include<bits/stdc++.h>
using namespace std;
vector<int> g[1005];
int ans = 1e9, dp[1005];
inline void dfs(int x, int fa){
vector<int> b;
for(int y : g[x]){
if(y == fa) continue;
dfs(y, x);
b.push_back(dp[y]);
}
sort(b.begin(), b.end(), greater<int>());
for(int i = 0; i < b.size(); i++) dp[x] = max(dp[x], b[i] + i + 1);
}
signed main(){
int N; cin >> N;
for(int i = 2; i <= N; i++){
int x; cin >> x;
g[i].push_back(x), g[x].push_back(i);
}
vector<int> num;
for(int i = 1; i <= N; i++){
memset(dp, 0, sizeof(dp));
dfs(i, 0);
if(dp[i] == ans) num.push_back(i);
else if(dp[i] < ans){
num.clear(); num.push_back(i);
ans = dp[i];
}
//cout << dp[i] << '\n';
}
cout << ans + 1 << '\n';
for(int x : num) cout << x << ' ';
return 0;
}

浙公网安备 33010602011771号