树形DP->苹果树(洛谷P2015)

题意:一个有根树,树枝上有苹果,问保留m个树枝,最多能保留多少个苹果。

分析:树形dp,给定了m树枝数,显然可能的状态集合应该是节点保留的边数以及对应的最大保留苹果数。不难设计出转移方程:
dp[u][i] = max(dp[u][i], dp[v][i - j - 1] + w);

    void solve(){
    int n, m;
    cin >> n >> m;

    vector<vector<pair<int, int>>> al(n + 1);
    for (int i = 1; i < n; ++i){
        int u, v, w;
        cin >> u >> v >> w;
        al[u].emplace_back(v, w);
        al[v].emplace_back(u, w);
    }

    vector<vector<int>> dp(n + 1, vector<int> (m + 1));
    function<void(int, int)> dfs = [&](int u, int p){
        for (const auto&[v, w] : al[u]){
            if (v != p){
                dfs(v, u);
                //这里一定要从后往前,跟背包一个道理,如果从前往后,那么i - j - 1可能重复利用了w
                //其实可以有个剪枝的操作,比如当前的节点u最多能保留的树枝的数量,以及节点v最多能保留的数值数量
                for (int i = m; i >= 0; --i){
                    for (int j = 0; j < i; ++j){
                        dp[u][i] = max(dp[u][i], dp[u][i - j - 1] + dp[v][j] + w);
                    }
                }
            }
        }
    };

    dfs(1, 0);

    cout << dp[1][m] << '\n';
}
posted @ 2024-01-18 10:13  _Yxc  阅读(13)  评论(0)    收藏  举报