vijos1100 加分二叉树

已知二叉树中序遍历序列,求所有可行树中的某种状态最优解。

二叉树中序遍历性质:1.遍历顺序:左节点->根->右节点。2.序列最后一个元素与深度遍历(二叉树前序遍历)时的最后一个元素相同3.同一个子树的遍历顺序是一个连续序列,此序列中的某个点都可能是该子树的根节点

dp[i][j]:[i,j]序列中的最优解。根据性质3,必须枚举所有可能的子节点。pre[i][j]:[i,j]序列子树的根节点是k

dp[i][j]=max{dp[i][k-1]*dp[k+1][j]+w[k]} pre[i][j]=k 

#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define sf scanf
#define pf printf
#define maxn 50
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
const ll mod=1000000007;
using namespace std;

int n,w[maxn],pre[maxn][maxn],dp[maxn][maxn];

void print(int i,int j){
    if(i>j) return;
    printf("%d",pre[i][j]);
    if(i!=j||i!=n) printf(" ");
    print(i,pre[i][j]-1);
    print(pre[i][j]+1,j);
}

int main(){
    scanf("%d",&n);
    mem(dp,0),mem(pre,-1);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]),dp[i][i]=w[i],pre[i][i]=i;
    for(int l=1;l<=n-1;l++){
        for(int i=1;i+l<=n;i++){
            int j=i+l;
            for(int k=i;k<=j;k++){
                if(dp[i][k-1]*dp[k+1][j]+w[k]>dp[i][j]){
                    if(k-1j) dp[k+1][j]=1;
                    dp[i][j]=dp[i][k-1]*dp[k+1][j]+w[k];
                    pre[i][j]=k;
                }
            }
        }
    }
    printf("%d\n",dp[1][n]);
    print(1,n);
    printf("\n");
}




你可能感兴趣的:(acm_动态规划)