2014819
加分二叉树【NOIP2003提高组】
Descripti on
设一个n个节点的二叉树tree的中序遍历为(1,2,3,…),n其中数字1,2,3,…,n 为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为di, tree及它的每个子树都有一个加分,任一棵子树 subtree (也包含tree本身)的加 分计算方法如下:
subtree的左子树的加分xsubtree的右子树的加分+ subtree的根的分数
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不 考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…)且加分最高的二叉树tree。要求输出:
(1) tree的最高加分
(2) tree的前序遍历
In put
第1行:一个整数n (n v 30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数 v 100)。
Output
第1行:一个整数,为最高加分(结果不会超过 4,000,000,000。 第2行:n个用空格隔开的整数,为该树的前序遍历。
Sample In put
5
5 7 1 2 10
Sample Output
145
3 1 2 4 5
题型:树型动规 用递归遍历整棵树。因为给出的是中序遍历,要求求出前序,所以实际上是区间动规。
在读入数据时把ans[i][i]初始化为i的分数,表示当一棵子树中只有一个节点时的加分。
把ans[i-1][i]初始化为i与i-1分数之和,root[i-1][i]为i-1 (这点很重要!因为有多解,所以 只有这样才能和标准输出一样)。
枚举每一个节点k作为根节点,递归查找 f(l,k-1)*f(k+1,j)+score[k],保存最大值为 max和k。
结束循环时,ans[i][j]=max ,root[i][j]=k;
最后递归输出即可。
代码:(变量名稍有不同)
#in cludeiostream
using n amespace std;
long an s[40][40],root[40][40],m ap[40]={0} ,n;
long dfs(lo ng x,lo ng y)
{
long s,sa,sb,a n=0,w;
for(s=x;s=y;s++){
if(x=s-1 s+1=y){
if(a ns[x][s-1]=0)sa=a ns[ x][s-1];
else sa=dfs(x,s-1);
if(a ns[s+1][y]=0)sb=a ns[s+1][y];
else sb=dfs(s+1,y);
if(sa*sb+map[s]a n){
an=sa*sb+map[s];
w=s;
}
}
}
an s[x][y]=a n;
root[x][y]=w;
return an;
}
void out(lo ng x,lo ng y)
{
if(root[x][y]!=0){
coutroot[x][y];
if(x!=y){
out(x,root [x] [y]-1);
out(root[x][y]+1,y);
}
}
}
int mai n()
{
long s;
cin?n;
memset(a ns,-1,sizeof(a ns));
for(s=1;s=n; s++){
cin map[s];
an s[s][s]=map[s];
root[s][s]=s;
an s[s_1][s]=map[s]+map[s_1];
root[s-1][s]=s-1;
}
coutdfs(1, n);
coute ndl;
out(1, n);
}
By逸仔
原创力文档

文档评论(0)