题目链接:https://www.luogu.com.cn/problem/P1040
大意是给出一个树的中序遍历,这个树每个子树都有一个加分,得分 = 左子树分数*右子树分数+根的分数。
在每个节点都有一个分数,第i个节点分数为di。其实就是给出的中序。求最大加分并输出先序遍历
根据题意的中序,我们可以将这个数划分为左右子树。f[i][i]就是这个根的分数。我们定义f[i][j]就是i到j这个子树的最大加分,中间用k来做一个区间dp
然后对树进行一个左右子树划分求出每个子树的最优值,最后的根权值肯定是最大加分
在每个最优的情况下,我们可以记录他的根。输出先序遍历就根据这个root数组来看。
code:
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize(2) #define ll long long inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*f; } const int nn = 50; int f[nn][nn],root[nn][nn]; int a[nn]; void print_path(int l,int r){ if(l>r) return; if(l==r){ cout<<l<<' '; return; } cout<<root[l][r]<<' '; print_path(l,root[l][r]-1); print_path(root[l][r]+1,r); } int main() { //cin.ignore(numeric_limits<streamsize>::max(),'\n') ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin>>n; int x; for(int i=1;i<=n;i++){ cin>>a[i]; f[i][i]=a[i];f[i][i-1]=1; } for(int i=n;i>=1;i--){//左边的一定是左子树的根 for(int j=i+1;j<=n;j++){ for(int k=i;k<=j;k++)//区间dp用于分割左右子树 { if(f[i][j]<f[i][k-1]*f[k+1][j]+f[k][k]){ f[i][j] = f[i][k-1]*f[k+1][j]+f[k][k]; root[i][j] = k; } } } } cout<<f[1][n]<<endl; print_path(1,n); }
同样的,我们可以对这个树进行搜索,先进行左子树,然后进行右子树,遍历到叶子就是1. 很容易可以想到是一个递归的思想。
code:
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize(2) #define ll long long inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*f; } int n,m; const int nn = 40; int f[nn][nn]; int root[nn][nn]; int a[nn]; int dfs(int l,int r){ if(l>r) return 1; if(f[l][r]) return f[l][r]; for(int i=l;i<=r;i++){ ll t = dfs(l,i-1)*dfs(i+1,r)+a[i]; if(f[l][r]<t){ f[l][r] = t; root[l][r] = i; } } return f[l][r]; } void print_path(int l,int r){ if(l>r) return; cout<<root[l][r]<<' '; print_path(l,root[l][r]-1); print_path(root[l][r]+1,r); } int main() { //cin.ignore(numeric_limits<streamsize>::max(),'\n') ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; root[i][i] = i; f[i][i] = a[i]; } cout<<dfs(1,n)<<endl; print_path(1,n); }