洛谷 [P1040]加分二叉树

来源:互联网 发布:淘宝top api易语言sdk 编辑:程序博客网 时间:2024/06/10 23:52

本题虽然是在树上的问题,但仍是区间DP的基本思路,因为给定区间是树的中序遍历,所以我们枚举左右端点,dp[i][j]表示从i到j号区间所表示的子树的最大分数,在转移的时候枚举根节点k,
有转移方程

if(dp[j][k-1]*dp[k+1][i]+num[k]>dp[j][i]){    dp[j][i]=dp[j][k-1]*dp[k+1][i]+num[k];    rt[j][i]=k;}

题目还要求输出先序遍历,只需在转移的时候更新root数组,rt[i][j]表示从i到j的区间所表示的子树的分数最大时的根节点。dfs输出即可。
由于题目问题,本题未AC,但思想仍可借鉴。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;int init(){    int rv=0,fh=1;    char c=getchar();    while(c<'0'||c>'9'){        if(c=='-') fh=-1;        c=getchar();    }    while(c>='0'&&c<='9'){        rv=(rv<<1)+(rv<<3)+c-'0';        c=getchar();    }    return fh*rv;}long long n,dp[50][50],rt[50][50],num[50];void dfs(int l,int r){    if(l>r) return;    if(l==r){        printf("%d ",rt[l][r]);        return;    }    printf("%d ",rt[l][r]);    dfs(l,rt[l][r]-1);    dfs(rt[l][r]+1,r);}int main(){    freopen("in.txt","r",stdin);    n=init();    for(int i=1;i<=n;i++){        for(int j=1;j<=n;j++){            dp[i][j]=1;        }    }    for(int i=1;i<=n;i++){        num[i]=init();        dp[i][i]=num[i];rt[i][i]=i;    }    for(int t=1;t<=n;t++){        for(int j=1;j+t<=n;j++){            int i=j+t;            for(int k=j;k<=i;k++){                if(dp[j][k-1]*dp[k+1][i]+num[k]>dp[j][i]){                    dp[j][i]=dp[j][k-1]*dp[k+1][i]+num[k];                    rt[j][i]=k;                }            }        }    }    cout<<dp[1][n]<<endl;    dfs(1,n);    fclose(stdin);    return 0;}