树形dp 洛谷P2015 二叉苹果树

洛谷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 二叉苹果树

上一篇:锤子线趋势策略


下一篇:杨桃电子之STM32