P1040 加分二叉树

https://www.luogu.com.cn/problem/P1040

n很小,可以树形dp或者区间dp。

设fij为从i到j的最大加分值,则有f[i][j]=max(f[i][k-1]*f[k+1][j]+f[k][k])。

有一个小技巧,将f[i][i-1]全部设置为1,这样的话搜索到叶子就也可以按照通式dp了。

对于输出前序遍历(根,左树,右树)我们再树形dp一下就行了。

树形dp比较清晰明了(但是耗内存)。不想写树形dp的话递推式如上。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 inline int read()
 7 {
 8     int x=0,w=1;char c=getchar();
 9     while(!isdigit(c)){
10         if(c=='-')w=-1;
11         c=getchar();
12     }
13     while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
14     return x*w;
15 }
16 const int maxn=35;
17 int n;
18 int f[maxn][maxn],a[maxn],ro[maxn][maxn];
19 int search(int l,int r)
20 {
21     if(l>r)return 1;
22     if(l==r){ro[l][r]=l;return f[l][r];}
23     if(f[l][r])return f[l][r];
24     for(int w,i=l;i<=r;i++)
25     {
26         w=search(l,i-1)*search(i+1,r)+f[i][i];
27         if(w>f[l][r])f[l][r]=w,ro[l][r]=i;
28     }
29     return f[l][r];
30 }
31 void print(int l,int r)
32 {
33     if(l>r)return ;
34     printf("%d ",ro[l][r]);
35     print(l,ro[l][r]-1);
36     print(ro[l][r]+1,r);
37 }
38 int main()
39 {
40     n=read();
41     for(int i=1;i<=n;i++)f[i][i]=read();
42     search(1,n);
43     printf("%d\n",f[1][n]);
44     print(1,n);//发扬先辈遗德,恢弘志士之气 
45     return 0;
46 }

 

posted @ 2020-06-09 22:11  Star_Cried  阅读(96)  评论(0编辑  收藏  举报