[CF1223E] Paint the Tree

## [CF1223E] Paint the Tree - 树形dp

### Description

在树上选取一些边,保证没有点度超过 k,求最大边权和

### Solution

用 $f[i][0/1]$ 表示处理了 i 的子树,i 的度小于等于 k 或 k-1 时的最大答案

注意在跳过边权 <0 的边

``` cpp
#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve()
{
    int n, k;
    cin >> n >> k;
    vector<vector<pair<int, int>>> g(n + 2);
    vector<vector<int>> f(n + 2, vector<int>(2));

    for (int i = 1; i < n; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
        g[v].push_back({u, w});
    }

    function<void(int, int)> dfs = [&](int p, int from) -> void {
        vector<int> vec;
        int sum = 0;
        for (auto [q, w] : g[p])
            if (q != from)
            {
                dfs(q, p);
                vec.push_back(f[q][1] + w - f[q][0]);
                sum += f[q][0];
            }
        sort(vec.begin(), vec.end());
        reverse(vec.begin(), vec.end());
        int first_k = 0, first_km1 = 0;
        for (int i = 0; i < k && i < vec.size() && vec[i] > 0; i++)
            first_k += vec[i];
        for (int i = 0; i + 1 < k && i < vec.size() && vec[i] > 0; i++)
            first_km1 += vec[i];
        f[p][0] = sum + first_k;
        f[p][1] = sum + first_km1;
    };

    dfs(1, 0);

    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans = max(ans, max(f[i][0], f[i][1]));
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin >> t;
    while (t--)
        solve();
}
原文地址:https://www.cnblogs.com/mollnn/p/14408458.html