【题目描述】
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
【输入格式】
第1行2个数,N和Q(1<=Q<=
N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
【输出格式】
剩余苹果的最大数量。
input
5 2
1 3 1
1 4 10
2 3 20
3 5 20
output
21
思路:树形动态规划。先用结构体建树,然后保存信息。这里要注意一条边的苹果是下面节点的w值(1号节点只需补上一条w为0的边即可),然后递归动态规划,f[i][j]代表i为根节点时保留j个树枝的最大苹果数
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int n,q;
bool vis[1005];
int a[15],b[15],c[15];
int f[1005][1005];
struct node{
int l,r,w;
}m[1005];
void buildtree(int x)
{
vis[x]=true;
for(int i=1;i<=n-1;i++)
{
if(a[i]==x||b[i]==x)
{
int k=a[i]+b[i]-x;
if(vis[k]==true)continue;
if(m[x].l==0)
{
m[x].l=k;m[k].w=c[i];
buildtree(k);
}
else
{
m[x].r=k;m[k].w=c[i];
buildtree(k);
}
}
}
}
void dp(int k)
{
f[k][1]=m[k].w;
if(m[k].l==0)return ;
dp(m[k].l);
dp(m[k].r);
for(int i=1;i<=q+1;i++)
for(int j=0;j<=i-1;j++)
{
if(f[k][i]<f[k][1]+f[m[k].l][j]+f[m[k].r][i-j-1])
f[k][i]=f[k][1]+f[m[k].l][j]+f[m[k].r][i-j-1];
}
}
int main()
{
memset(vis,false,sizeof(vis));
cin>>n>>q;
for(int i=1;i<=n-1;i++)
cin>>a[i]>>b[i]>>c[i];
buildtree(1);
dp(1);
cout<<f[1][q+1];
return 0;
}