Luogu 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行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出格式:
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
输入输出样例
输入样例#1: 复制
5 5 7 1 2 10
输出样例#1: 复制
145 3 1 2 4 5
参考博客https://www.cnblogs.com/L-Memory/p/7353689.html
1 //2018年4月5日11:17:08 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 typedef long long ll; 6 7 const int N = 31; 8 int n; 9 ll f[N][N]; 10 int num[N][N]; 11 int w[N]; 12 13 void find(int x, int y){ 14 if(x <= y){ 15 printf("%d ", num[x][y]); 16 find(x, num[x][y]-1); 17 find(num[x][y]+1, y); 18 } 19 } 20 21 int main(){ 22 scanf("%d", &n); 23 for(int i=0; i<=n; i++) 24 for(int j=0; j<=n; j++){ 25 f[i][j] = 1; num[i][i] = i; 26 } 27 for(int i=1; i<=n; i++){ 28 scanf("%d", &f[i][i]); 29 } 30 for(int i=n; i>=1; i--) //***** 31 for(int j=i+1; j<=n; j++) 32 for(int k=i; k<=j; k++){ 33 if(f[i][j] < f[i][k-1]*f[k+1][j] + f[k][k]) 34 f[i][j] = f[i][k-1]*f[k+1][j] + f[k][k], num[i][j] = k; 35 } 36 printf("%lld\n", f[1][n]); 37 find(1, n); 38 39 return 0; 40 }
还有记忆化搜索的写法,可以参考https://www.cnblogs.com/oscar-cnblogs/p/8670212.html
1 //2018年4月5日11:57:39 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 6 typedef long long ll; 7 8 const int N = 31; 9 int a[N]; 10 int f[N][N]; 11 int root[N][N]; 12 int n; 13 14 int dfs(int l, int r){ 15 if(l > r) return 1; 16 if(f[l][r] > 0) return f[l][r]; 17 if(l == r){ 18 root[l][r] = l; 19 f[l][r] = a[l]; 20 return f[l][r]; 21 } 22 for(int i=l; i<=r; i++){ 23 int res = dfs(l, i-1)*dfs(i+1, r) + a[i]; 24 if(res > f[l][r]){ 25 f[l][r] = res; 26 root[l][r] = i; 27 } 28 } 29 return f[l][r]; 30 31 } 32 33 void print(int l, int r){ 34 if(l > r) return; 35 if(l == r){ 36 printf("%d ", root[l][r]); 37 return; 38 } 39 printf("%d ", root[l][r]); 40 print(l, root[l][r]-1); 41 print(root[l][r]+1, r); 42 } 43 44 45 int main(){ 46 scanf("%d", &n); 47 for(int i=1; i<=n; i++) scanf("%d", &a[i]); 48 printf("%d\n", dfs(1, n)); 49 print(1, n); 50 51 return 0; 52 }