题解: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;
}
posted @ 2026-08-22 17:15  Antony_pico  阅读(6)  评论(0)    收藏  举报