[洛谷P1040][题解]加分二叉树

题目戳我!

这个题的难度是绿色,众所周知青菜是绿色的,所以这题一定很菜,实际上确实是(你不还是看了题解)

我们可以设计出这样一个状态:f[l][r]代表从l到r的最高加分,结果就是f[1][n]

怎样转移?

一棵子树肯定要有根,所以我们就枚举根!

在一段区间[i,j]里,揪出来一个根k,然后转移:f[l][r]=max(f[l][k-1]*f[k+1][r]+f[k][k])

其中f[k][k]显然就是自身的权值了

因为揪出根之后剩下的区间一定比之前小,所以要按长度从小往大枚举区间

输出的话记录一下i到j这棵子树揪出来的根就好啦~

Code:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<ctime>
 5 #include<cstring>
 6 #include<iostream>
 7 #include<algorithm>
 8 #include<stack>
 9 #include<queue>
10 #include<vector>
11 #include<bitset>
12 #include<set>
13 #include<map>
14 #define LL long long
15 #define rg register
16 #define us unsigned
17 #define eps 1e-6
18 #define INF 0x3f3f3f3f
19 #define ls k<<1
20 #define rs k<<1|1
21 #define tmid ((tr[k].l+tr[k].r)>>1)
22 #define nmid ((l+r)>>1)
23 #define Thispoint tr[k].l==tr[k].r
24 #define pushup tr[k].wei=tr[ls].wei+tr[rs].wei
25 #define pub push_back
26 #define lth length
27 #define int long long
28 using namespace std;
29 inline void Read(int &x){
30     int f=1;
31     char c=getchar();
32     x=0;
33     while(c<'0'||c>'9'){
34         if(c=='-')f=-1;
35         c=getchar();
36     }
37     while(c>='0'&&c<='9'){
38         x=(x<<3)+(x<<1)+c-'0';
39         c=getchar();
40     }
41     x*=f;
42 }
43 #define N 40
44 int n,f[N][N],pr[N][N];
45 inline void Initi(){
46     Read(n);
47     for(rg int i=1;i<=n;i++){
48         Read(f[i][i]);
49         pr[i][i]=i;
50     }
51 }
52 inline void Solve(){
53     for(rg int len=1;len<n;len++){
54         for(rg int l=1;l+len<=n;l++){
55             int r=l+len;
56             //初始情况
57             //加分:没有左子树一定最小 
58             //根:先记上左端点 
59             f[l][r]=f[l+1][r]+f[l][l],pr[l][r]=l;
60             for(rg int k=l+1;k<r;k++){
61                 if(f[l][r]<f[l][k-1]*f[k+1][r]+f[k][k]){
62                     f[l][r]=f[l][k-1]*f[k+1][r]+f[k][k];
63                     pr[l][r]=k;//转移+记录 
64                 }
65             }
66         }
67     }
68 }
69 inline void Print(int l,int r){
70     if(l>r)return;
71     printf("%lld ",pr[l][r]);
72     if(l!=r){
73         Print(l,pr[l][r]-1);
74         Print(pr[l][r]+1,r);
75     }else return;
76 }
77 signed main(){
78     Initi();
79     Solve();
80     printf("%lld\n",f[1][n]);
81     Print(1,n);
82     return 0;    
83 }

猜你喜欢

转载自www.cnblogs.com/juruoajh/p/12520196.html