P1040 加分二叉树(区间DP&记忆化搜索)
思路:超级经典的区间 题。也可用记忆化搜索做,简单来说就是枚举树根,然后不断向外扩展,打印先序遍历就用“根左右“的方式递归就 了。注意题目要求空子树是1.
以 为根,则 的左子树是空。
区间 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=35;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
inline void read(int &x){
x=0;int w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<3)+(x<<1)+(ch&15);
x*=w;
}
ll dp[N][N];
int n,rt[N][N],x;
void Print(int l,int r){
if(l>r) return;
printf("%d ",rt[l][r]);
Print(l,rt[l][r]-1);
Print(rt[l][r]+1,r);
}
int main(){
read(n);
for(int i=1;i<=n;i++) read(x),dp[i][i]=x,rt[i][i]=i,dp[i][i-1]=1;
for(int k=2;k<=n;k++)
for(int l=1;l+k-1<=n;l++){
int r=l+k-1;
for(int i=l;i<=r;i++){
ll tmp=dp[l][i-1]*dp[i+1][r]+dp[i][i];
if(dp[l][r]<tmp){
rt[l][r]=i;
dp[l][r]=tmp;
}
}
}
printf("%lld\n",dp[1][n]);
Print(1,n);
return 0;
}
记忆化搜索 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=35;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
inline void read(int &x){
x=0;int w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<3)+(x<<1)+(ch&15);
x*=w;
}
ll ans[N][N];
int n,a[N],rt[N][N];
ll dfs(int l,int r){
if(ans[l][r]) return ans[l][r];
if(l>r) return 1;
if(l==r){
rt[l][l]=l;
return ans[l][l]=a[l];
}
ll sum=0;
for(int i=l;i<=r;i++){
ll tmp=dfs(l,i-1)*dfs(i+1,r)+a[i];
if(tmp>sum) sum=tmp,rt[l][r]=i;
}
return ans[l][r]=sum;
}
void Print(int l,int r){
if(l>r) return;
printf("%d ",rt[l][r]);
Print(l,rt[l][r]-1);
Print(rt[l][r]+1,r);
}
int main(){
read(n);
for(reg int i=1;i<=n;i++) read(a[i]);
printf("%lld\n",dfs(1,n));
Print(1,n);
return 0;
}