二叉苹果树
题目描述
有一棵苹果树,如果树枝有分叉,一定是分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[u][i]=max(f[u][i],f[u][i−j−1]+f[v][j]+e[i].w)( 1≤i≤min(q,sz[u]),0≤j≤min(sz[v],i−1) )
【code】
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 int n,q,l[105],r[105],f[105][105],vis[105][105],a[105]; 6 inline int Max(int a,int b){ 7 return a>b?a:b; 8 } 9 void BuildTree(int v){ 10 for(register int i=1;i<=n;i++) 11 if(vis[v][i]>=0){ 12 l[v]=i; 13 a[i]=vis[v][i]; 14 vis[v][i]=vis[i][v]=-1; 15 BuildTree(i); 16 break; 17 } 18 for(register int i=1;i<=n;i++) 19 if(vis[v][i]>=0){ 20 r[v]=i; 21 a[i]=vis[v][i]; 22 vis[v][i]=vis[i][v]=-1; 23 BuildTree(i); 24 break; 25 } 26 } 27 inline int dp(int i,int j){ 28 if(j==0)return 0; 29 if(l[i]==0&&r[i]==0)return a[i]; 30 if(f[i][j]>0)return f[i][j]; 31 for(register int k=0;k<j;k++) 32 f[i][j]=Max(f[i][j],dp(l[i],k)+dp(r[i],j-k-1)+a[i]); 33 return f[i][j]; 34 } 35 int main(){ 36 //freopen("2015.in","r",stdin); 37 //freopen("2015.out","w",stdout); 38 scanf("%d%d",&n,&q); 39 q++; 40 for(register int i=1;i<=n;i++) 41 for(register int j=1;j<=n;j++) 42 vis[i][j]=-1; 43 for(register int i=1;i<n;i++){ 44 int x,y,z; 45 scanf("%d%d%d",&x,&y,&z); 46 vis[x][y]=vis[y][x]=z; 47 } 48 BuildTree(1); 49 printf("%d\n",dp(1,q)); 50 return 0; 51 }