类型:树形动态规划[经典]
状态:dp(i,j)表示以i为根的子树(还包括i与i的父亲这条边)内,保存j条边最多可以有多少苹果
转移方程:dp(i,j) = max(dp(i.left,k) + dp(i.right,j-1-k)) + i.val (0<=k<=j-1)
思路:输入处理,递归建树,树内dp记忆化搜索实现,输出结果
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define MAX 110
int dp[MAX][MAX],apple[MAX][MAX],N,Q;
bool vis[MAX];
struct node{
int left,right;
int val;
}tree[MAX];
void creat(int root) {
vis[root] = true;
for(int i = 1; i <= N; ++i)
if(!vis[i] && apple[root][i] != -1) {
if(tree[root].left != 0)
tree[root].right = i;
else
tree[root].left = i;
tree[i].val = apple[root][i];
creat(i);
}
}
int tree_dp(int i,int j) {
int k;
if(dp[i][j] != -1)
return dp[i][j];
if(j == 0 || i == 0) //!!!
return dp[i][j] = 0;
for(dp[i][j] = 0, k = 0; k != j; ++k){
int ls = tree_dp(tree[i].left, k);
int rs = tree_dp(tree[i].right, j-1-k);
if(dp[i][j] < ls + rs)
dp[i][j] = ls + rs;
}
return dp[i][j] += tree[i].val;
}
int main() {
int a,b,c,i;
cin>>N>>Q;
memset(apple, -1, sizeof(apple));
for(Q++, i = 1; i != N; ++i){
cin>>a>>b>>c;
apple[a][b] = apple[b][a] = c;
}
memset(dp, -1, sizeof(dp));
creat(1);
cout<<tree_dp(1, Q)<<endl;
return 0;
}