版权声明:反正也没有人会转,下一个 https://blog.csdn.net/drtlstf/article/details/83011082
Description
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)。这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
Input
第1行2个数,N和Q(1<=Q<= N,1<N<=100)N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
Output
一个数,最多能留住的苹果的数量。
Sample Input
5 2
1 3 1
1 4 10
2 3 20
3 5 20
Sample Output
21
树形DP的一道很经典的题.
#include <iostream>
#include <vector>
#define SIZE 110
using namespace std;
struct edge
{
int to, cap;
};
vector<edge> graph[SIZE];
int dp[SIZE][SIZE], m; // DP[I][J]表示第I个节点和它的子树保留J个树枝剩余苹果的最大值.
int dfs(int u, int pre) // DP过程
{
int i, j, k, v, w, childcount = 0;
for (i = 0; i < graph[u].size(); ++i)
{
v = graph[u][i].to;
if (v == pre) // 确保不是回到了前一个点
{
continue;
}
w = graph[u][i].cap;
childcount += dfs(v, u) + 1;
for (j = min(childcount, m); j >= 1; --j)
{
for (k = min(j, childcount); k >= 1; --k)
{
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k-1] + w); // 条件转移方程
}
}
}
return childcount; // 顺便返回二子数
}
int main(int argc, char** argv)
{
int n, u, v, w, i;
scanf("%d%d", &n, &m);
for (i = 1; i < n; ++i)
{
scanf("%d%d%d", &u, &v, &w);
graph[u].push_back({v, w}); // 建图
graph[v].push_back({u, w});
}
dfs(1, -1);
printf("%d", dp[1][m]);
return 0;
}