您的位置:首页 > 其它

Code[VS] 1090 加分二叉树

2015-02-21 12:24 302 查看
【题意】

已知:一颗树tree,n,d

条件:①有结点1..n,每个点有分数d[i],tree满足中序遍历为1..n

②子树subtree的加分计算方法为:左子树加分×右子树加分+根的分数

③空子树加分为1,叶子的加分就是叶节点本身的分数,不考虑它的空子树。

求:一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree,输出 ①tree的最高加分 ②tree的前序遍历

【构思】

树有无后效性-->树形DP;

由于满足中序遍历,所以一颗子树的结点编号必然在一连续区间内;

设f[l][r]表示区间[l,r]的最大加分,rt[l][r]为最大加分时rt是什么;

边界:f[l][r]=1(l>r),f[l][r]=d[l](l=r)

方程:f[l][r]=max(f[l][i-1]+f[i+1][r]+d[i])

结果即f[1]
,且得到rt后直接可以建树,2问都解决了;

时间复杂度:O(n^3)

空间复杂度:O(n^2)

【实现】

#include <cstdio>

#include <cstring>

#include <cstdlib>

#define MIN -5000000000

using namespace std;

const int N=31;

int n,d
,rt

,s
;

long long f

;

void init(void)

{

scanf("%d",&n);

for (int i=1;i<=n;i++) scanf("%d",&d[i]);

}

long long DFS(int l,int r)

{

if (l>r) return 1;

if (f[l][r]^MIN) return f[l][r];

for (int i=l;i<=r;i++)

{

long long t=DFS(l,i-1)*DFS(i+1,r)+d[i];

if (f[l][r]<t)

{

f[l][r]=t;

rt[l][r]=i;

}

}

return f[l][r];

}

void Get(int l,int r)

{

if (l>r) return;

if (l==r) {s[++s[0]]=l;return;}

s[++s[0]]=rt[l][r];

Get(l,rt[l][r]-1);

Get(rt[l][r]+1,r);

}

void work(void)

{

for (int i=1;i<=n;i++)

for (int j=i;j<=n;j++) f[i][j]=(i==j?d[i]:MIN);

printf("%lld\n",DFS(1,n));

Get(1,n);

for (int i=1;i<n;i++) printf("%d ",s[i]);

printf("%d\n",s
);

}

int main(void)

{

init();

work();

return 0;

}

【回顾】

[1] DP无后效性的判定 ①空间的单项变化 ②数值的单调变化 ③树结构

[2] 树的遍历的性质

①单独性质

前序遍历 第1个为根 一段区间在后[i,i+size[i]-1]

中序遍历 当序列满足1..n时,子树也为连续区间 排序

后序遍历 最后为根 一段区间在前[i-size[i]+1,i]

②关联性质

遍历长度相同

[3] 树的遍历:搜索

[4] 数据类型大的变量可以加小的变量,小的不能加大的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: