加分二叉树解题报告.docx

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)

1亿VIP精品文档

相关文档