chenfy27的刷题记录

导航

luoguP2015 二叉苹果树

给定一棵N个节点的苹果树,根节点编号为1。如果树枝有分叉,一定是分二叉。已知节点a与b的边权为w[a][b]。求一棵树,最多有Q条边,并且边权之和最大。
1<=Q<N<=100; 0<=w[i][j]<=3E4

分析:Q条边的树对应Q+1个节点,转化为节点数限制,可以用树上背包的方法来做。记dp[x][j]表示以x为根,选择节点数不超过j的最大权值之和,对于节点x,如果要选其子节点i,那么必须选上x,可以枚举子节点的节点数进行递推。

#include <bits/stdc++.h>
using i64 = long long;

void solve() {
    int N, Q;
    std::cin >> N >> Q;
    std::vector<std::vector<int>> adj(N);
    std::vector<std::vector<int>> w(N, std::vector<int>(N));
    for (int i = 1; i < N; i++) {
        int x, y, z;
        std::cin >> x >> y >> z;
        x--, y--;
        w[x][y] = w[y][x] = z;
        adj[x].push_back(y);
        adj[y].push_back(x);
    }

    std::vector<std::vector<int>> dp(N, std::vector<int>(Q + 2));

    auto dfs = [&](auto self, int x, int p) -> void {
        for (int i = 1; i <= Q + 1; i++) {
            dp[x][i] = w[x][p];
        }
        for (auto i : adj[x]) if (i != p) {
            self(self, i, x);
            for (int j = Q + 1; j >= 1; j--) {
                for (int k = 0; k < j; k++) {
                    dp[x][j] = std::max(dp[x][j], dp[i][k] + dp[x][j - k]);
                }
            }
        }
    };

    dfs(dfs, 0, 0);
    std::cout << dp[0][Q + 1] << "\n";
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

posted on 2024-11-03 15:44  chenfy27  阅读(3)  评论(0编辑  收藏  举报