1. 程式人生 > >樹形dp 洛谷P2015 二叉蘋果樹

樹形dp 洛谷P2015 二叉蘋果樹

左右子樹 break 方程 return 我們 pan 16px mes ora

洛谷P2015 二叉蘋果樹 很明顯的一道樹形dp。

需要保留的枝條有q條,所以就要保留j=q+1個節點,我們可以分三種情況討論:

1、樹根的左子樹為空,只保留右子樹,這時右子樹保留j-1個節點。

2、樹根的右子樹為空,只保留左子樹,這時左子樹保留j-1個節點。

3、左右子樹都非空,設左子樹保留k個節點,那麽右子樹保留j-1-k個節點。

設樹根為i,左子樹為l[i],右子樹為r[i],則狀態轉移方程為:

f[i][j]=max(f[i][j],f(l[i],j)+f(r[i],j-1-k)+a[i]);

附上代碼

 1 #include<iostream>
 2 #include<cstdio>
 3
#include<cmath> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 int n,q; 8 int a[105]; 9 int ju[105][105]; 10 int f[105][105]; 11 int r[105]; 12 int l[105]; 13 int aa,bb,cc; 14 inline int dp(int x,int y)//樹形dp 15 { 16 if(y==0) return 0; 17 if(r[x]==0&&l[x]==0
) return a[x]; 18 if(f[x][y]!=0) return f[x][y]; 19 for(int k=0;k<=y-1;k++) 20 { 21 f[x][y]=max(f[x][y],dp(l[x],k)+dp(r[x],y-1-k)+a[x]);//狀態轉移 22 } 23 return f[x][y]; 24 } 25 inline void maketree(int v)//建樹 26 { 27 for(int i=1;i<=n;i++)//左子樹 28 { 29 if(ju[i][v]>=0
) 30 { 31 l[v]=i;a[i]=ju[i][v]; 32 ju[i][v]=ju[v][i]=-1; 33 maketree(i); 34 break; 35 } 36 } 37 for(int i=1;i<=n;i++)//右子樹 38 { 39 if(ju[i][v]>=0) 40 { 41 r[v]=i;a[i]=ju[v][i]; 42 ju[v][i]=ju[i][v]=-1; 43 maketree(i); 44 break; 45 } 46 } 47 } 48 int main() 49 { 50 cin>>n>>q;q++; 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=n;j++) 53 ju[i][j]=-1; 54 for(int i=1;i<=n-1;i++) 55 { 56 scanf("%d%d%d",&aa,&bb,&cc); 57 ju[aa][bb]=ju[bb][aa]=cc; 58 } 59 maketree(1);//以1為節點建樹 60 printf("%d",dp(1,q)); 61 return 0; 62 }

樹形dp 洛谷P2015 二叉蘋果樹