题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)。这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。 给定需要保留的树枝数量,求出最多能留住多少苹果。
输入格式
第1行2个数,N和Q(1<=Q<= N,1
输出格式
一个数,最多能留住的苹果的数量。
样例数据
input
5 2
1 3 1
1 4 10
2 3 20
3 5 20
output
21
Solution
表示到第i个节点保留j条枝条的最大苹果数量
因为是二叉树,所以我们枚举左孩子中保留的枝条数量,可以通过相减得到右孩子的枝条个数
状态转移方程:
对于x节点下的子节点j,对j保留多少枝条最优进行dp
在这里好好说明下,因为建树是我们是按照递归建的树。
进行比较时,f[x][j]都是前面选择除i外的子节点得到的最优解结果
所以dp的时候不可能重复或者漏掉某节点
代码:
//By Bibi
/// .-~~~~~~~~~-._ _.-~~~~~~~~~-.
/// __.' ~. .~ `.__
/// .'// \./ \\`.
/// .'// | \\`.
/// .'// .-~"""""""~~~~-._ | _,-~~~~"""""""~-. \\`.
/// .'//.-" `-. | .-' "-.\\`.
/// .'//______.============-.. \ | / ..-============.______\\`.
/// .'______________________________\|/______________________________`.
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN=110;
int inline read(){
int sum=0,flag=1;
char c;
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
return sum*flag;
}
int n,q;
int v[MAXN];
struct edge{
int y,next,v;
}e[MAXN<<1];
int f[MAXN][MAXN];
int link[MAXN];
int tot;
void inline insert(int x,int y,int v){
e[++tot].y=y;e[tot].v=v;e[tot].next=link[x];link[x]=tot;
}
void inline init(){
n=read(),q=read();
int x,y,v;
rep(i,1,n-1){
x=read();y=read();v=read();
insert(x,y,v);
insert(y,x,v);
}
}
int inline DP(int x,int fa){
int ans=0;
for(int i=link[x];i;i=e[i].next){
int y=e[i].y;
if(y==fa) continue;
int v=e[i].v;
ans+=DP(y,x)+1;
dep(j,min(ans,q),1)
dep(k,min(ans,j),1){
f[x][j]=max(f[x][j],f[x][j-k]+f[y][k-1]+v);
}
}
return ans;
}
int main(){
init();
DP(1,0);
printf("%d",f[1][q]);
return 0;
}