您的位置:首页 > 其它

sjtu 1077 加分二叉树

2013-03-18 19:05 766 查看
树型DP入门题

题目链接:http://acm.sjtu.edu.cn/OnlineJudge/problem/1077

•设f(i,j)中序遍历为i,i+1,…,j的二叉树的最大加分,则有:
f(i,j)=max{f[i,k-1]*f[k+1,j] +d[k]}

•显然 f(i,i)=d[i]
•答案为f(1,n)
•1<=i<=k=<=j<=n
•时间复杂度 O(n3)
•要构造这个树,只需记录每次的决策值,令b(i,j)=k,表示中序遍历为i,i+1,…,j的二叉树的取最优决策时的根结点为k
最后前序遍历这个树即可。

/*
树型DP
*/
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define MAX 35
#define INF 0x3f3f3f3f

long long dp[MAX][MAX];
int p[MAX][MAX];
int a[MAX];
queue<int>q;

long long dfs(int i ,int j)
{
if(i>j) return dp[i][j]=1;
if(dp[i][j]!=-1) return dp[i][j];
dp[i][j]=-INF;
for(int k=i; k<=j; k++)
{
long long t1=dfs(i,k-1);
long long t2=dfs(k+1,j);
if(t1*t2+a[k] > dp[i][j])
{
dp[i][j]=t1*t2+a[k];
p[i][j]=k;
}
}
return dp[i][j];
}

void travel(int i ,int j)
{
if(i>j) return ;
if(i==j)
{
q.push(i);
return ;
}
int k=p[i][j];
q.push(k);
travel(i,k-1);
travel(k+1,j);
}

int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
memset(p,-1,sizeof(p));
memset(dp,-1,sizeof(dp));
for(int i=1; i<=n; i++)
{
dp[i][i]=a[i];
p[i][i]=i;
}
dfs(1,n);
printf("%lld\n",dp[1]
);
while(!q.empty()) q.pop();
travel(1,n);
printf("%d",q.front());
q.pop();
while(!q.empty())
{
printf(" %d",q.front());
q.pop();
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: