题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5 / 3 4 / 1 现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
输入输出格式
输入格式:
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
输出格式:
一个数,最多能留住的苹果的数量。
输入输出样例
输入样例#1:
5 2 1 3 1 1 4 10 2 3 20 3 5 20
输出样例#1:
21
分析
f[i][j]表示以i为根的子树上保留j个树枝所取得的最大值。因为是二叉树嘛,只与两个儿子有关,枚举每个儿子保留多少个就好啦。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cctype> using namespace std; inline void read(int &x){ int f=1; x=0; char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} x= f<0? ~x+1:x; } int n,Q; int mp[105][105],w[105][105],son[105][105],f[105][105]; inline void dfs(int x,int fa){ for(int i=1;i<=mp[x][0];++i){ if(mp[x][i]==fa) continue; son[x][++son[x][0]]=mp[x][i]; dfs(mp[x][i],x); } } int dp(int x,int y){ if(f[x][y]!=-1) return f[x][y]; if(y==0) return f[x][y]=0; int lc=son[x][1],rc=son[x][2]; f[x][y]=max(dp(lc,y-1)+w[x][lc],dp(rc,y-1)+w[x][rc]); for(int i=0;i<=y-2;++i) f[x][y]=max(f[x][y],dp(lc,i)+dp(rc,y-2-i)+w[x][lc]+w[x][rc]); return f[x][y]; } int main(){ read(n);read(Q); int x,y,v; for(int i=1;i<n;++i){ read(x);read(y);read(v); mp[x][++mp[x][0]]=y; mp[y][++mp[y][0]]=x; w[x][y]=w[y][x]=v; } dfs(1,-1); memset(f,-1,sizeof(f)); int ans=dp(1,Q); printf("%d ",ans); return 0; }