洛谷 P1040 加分二叉树
题目描述
设一个 n 个节点的二叉树tree的中序遍历为( 1,2,3,…,n ),其中数字 1,2,3,…,n 为节点编号。每个节点都有一个分数(均为正整数),记第 i 个节点的分数为 di,tree 及它的每个子树都有一个加分,任一棵子树 subtree (也包含 tree 本身)的加分计算方法如下:
subtree 的左子树的加分× subtree 的右子树的加分+ subtree 的根的分数。
若某个子树为空,规定其加分为 1 ,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为( 1,2,3,…,n )且加分最高的二叉树 tree 。要求输出;
(1) tree 的最高加分
(2) tree 的前序遍历
输入输出格式
输入格式:
第 1 行: 1 个整数 n (n < 30) ,为节点个数。
第 2 行: n 个用空格隔开的整数,为每个节点的分数(分数 <100 )。
输出格式:
第 1 行: 1 个整数,为最高加分(Ans ≤ 4,000,000,000 )。
第 2 行: n 个用空格隔开的整数,为该树的前序遍历。
输入输出样例
输入样例#1: 复制
5 5 7 1 2 10
输出样例#1: 复制
View Code
145 3 1 2 4 5
思路:用f[i][j]表示中序遍历为 i 到 j 的一棵树的最大加分
则:f[i][j]=max{f[i][k]*f[k+1][j]+f[k][k],k为根节点}
用d[i][j]记录区间[i,j]的根节点, write(i,j)输出区间[i,j]这棵树
则:write(i,j)==>wrie(i,d[i][j]-1)+d[i][j]+write(d[i][j]+1,j)
#include<cstdio> #define M 55 using namespace std; int n; int f[M][M],d[M][M]; void write(int l, int r) { if(l > r) return; printf("%d ", d[l][r]); write(l, d[l][r]-1); write(d[l][r]+1, r); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &f[i][i]); d[i][i] = i, f[i+1][i] = 1; } f[1][0] = 1; for(int k = 2; k <= n; k++) for(int s = 1; s+k-1 <= n; s++) for(int e = s+k-1,j = s; j <= e; j++) if(f[s][e] < f[s][j-1] * f[j+1][e] + f[j][j]) { f[s][e] = f[s][j-1] * f[j+1][e] + f[j][j]; d[s][e] = j; } printf("%d\n", f[1][n]); write(1, n); return 0; }