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;
}