10153. 「一本通 5.2 例 1」二叉苹果树

题意

有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共 $N$ 个节点,标号 $1$ 至 $N$,树根编号一定为 $1$。

tree.png

我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

思路

设$f[i][j]$表示以i为根节点,保留j个节点的最大苹果数量 $$f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1)$$ $$f[i][j]=0(0<i<=n,0<=j<=Q+1)$$ $$f[i][j]=ai$$ $$Answer:f[1][Q+1]$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
char ch=getchar();ll res=0,f=1;
while(ch<'0'ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
ll n,Q,f[110][110],a[110],l[110],r[110],mp[110][110];
void MakeTree(int x){
for(int i=1;i<=n;i++){
if(mp[x][i]!=-1){
l[x]=i;a[i]=mp[x][i];
mp[x][i]=mp[i][x]=-1;
MakeTree(i);
break;
}
}//Make Left Son
for(int i=1;i<=n;i++){
if(mp[x][i]!=-1){
r[x]=i;a[i]=mp[x][i];
mp[x][i]=mp[i][x]=-1;
MakeTree(i);
break;
}
}//Make Right Son
}
int DP(int x,int j){

if(j==0){f[x][j]=0;return 0;}
if((!l[x])&&(!r[x])){f[x][j]=a[x];return a[x];}
if(f[x][j]>0) return f[x][j];
for(int k=0;k<j;k++) f[x][j]=max(f[x][j],DP(l[x],k)+DP(r[x],j-k-1)+a[x]);
return f[x][j];
}
int main(){
n=read();Q=read();Q++;
memset(mp,-1,sizeof(mp));
for(int i=1;i<=n-1;i++){
int x=read(),y=read(),z=read();
mp[y][x]=mp[x][y]=z;
}
MakeTree(1);
write(DP(1,Q));putchar('\n');
/*
cout<<"-----------------------------------"<<endl;
for(int i=1;i<=n;i++){
cout<<"Node "<<i<<":\n";
cout<<"Left Son:"<<l[i]<<" Right Son:"<<r[i]<<endl;
cout<<"Val:"<<a[i]<<endl;
cout<<"DP :\n";
for(int j=0;j<=Q;j++){
cout<<"Has "<<j<<":"<<f[i][j]<<endl;
}
cout<<endl;
}
*/
return 0;
}
//设f[i][j]表示以i为根节点,保留j个节点的最大苹果数量
//f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1)
//f[i][j]=0(0<i<=n,0<=j<=Q+1)
//f[i][j]=a[i](j!=0&&l[i]==0&&r[i]==0)
//Answer:f[1][Q+1]
/*
Sample Input:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
Sample Output:
21
*/