洛谷 P2015 二叉苹果树(树形dp)
传送门
解题思路
很显然的树形dp,设dp[i][j]表示在子树i上保留j条边的最大苹果树,从儿子节点转移过来即可,注意若某个儿子不选,则以此儿子为根的子树都不能选。
还有就是因为是二叉树,可以提前遍历一遍求出每个点的两个或零个儿子,就不用在求dp时倒序枚举了,算是一个小技巧趴。
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 using namespace std; 7 int n,q,cnt,p[105],dp[105][105],son[105][3]; 8 struct node{ 9 int v,value,next; 10 }e[205]; 11 void insert(int u,int v,int value){ 12 cnt++; 13 e[cnt].v=v; 14 e[cnt].value=value; 15 e[cnt].next=p[u]; 16 p[u]=cnt; 17 } 18 void dfs(int u,int fa){ 19 for(int i=p[u];i!=-1;i=e[i].next){ 20 int v=e[i].v; 21 if(v==fa) continue; 22 son[u][++son[u][0]]=i; 23 dfs(v,u); 24 } 25 } 26 void dfs2(int u){ 27 if(son[u][0]==0) return; 28 int v1=e[son[u][1]].v; 29 int v2=e[son[u][2]].v; 30 dfs2(v1); 31 dfs2(v2); 32 for(int i=1;i<=q;i++){ 33 dp[u][i]=max(dp[v1][i-1]+e[son[u][1]].value,dp[v2][i-1]+e[son[u][2]].value); 34 for(int j=0;j<=i-2;j++) dp[u][i]=max(dp[u][i],dp[v1][j]+dp[v2][i-2-j]+e[son[u][1]].value+e[son[u][2]].value); 35 } 36 } 37 int main() 38 { 39 memset(p,-1,sizeof(p)); 40 cin>>n>>q; 41 for(int i=1;i<=n-1;i++){ 42 int u,v,value; 43 cin>>u>>v>>value; 44 insert(u,v,value); 45 insert(v,u,value); 46 } 47 dfs(1,-1); 48 dfs2(1); 49 cout<<dp[1][q]; 50 return 0; 51 }