加分二叉树
加分二叉树
Description
设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数 若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出:
(1)tree的最高加分
(2)tree的前序遍历
Input
第1行:一个整数n(n<30)为节点个数。 第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
Output
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。 第2行:n个用空格隔开的整数,为该树的前序遍历。
Sample Input
5
5 7 1 2 10
Sample Output
145
3 1 2 4 5
HINT
Source
#include <bits/stdc++.h>
using namespace std;
int n, a[101];
int opt[101][101];
int f[101][101];
int solve (int p, int q) {
if (f[p][q] != -1) {
return f[p][q];
}
if (p > q) {
f[p][q] = 1;
return 1;
}
else if (p == q) {
opt[p][p] = p;
f[p][q] = a[p];
return f[p][q];
}
int ans = 0;
for (int r = p; r <= q; r ++) {
int res = solve(p, r - 1) * solve(r + 1, q) + a[r];
if (res > ans) {
ans = res;
opt[p][q] = r;
}
}
f[p][q] = ans;
return f[p][q];
}
void proot(int p, int q) {
if (p > q) {
return ;
}
printf("%d ", opt[p][q]);
proot(p, opt[p][q] - 1);
proot(opt[p][q] + 1, q);
}
int main() {
cin >> n;
memset(f, -1, sizeof(f));
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
cout << solve(1, n) << endl;
proot(1, n);
return 0;
}
递归写法
#include <bits/stdc++.h>
using namespace std;
int n, a[101];
int opt[101][101];
int f[101][101];
void print(int p, int q) {
if (p > q) return ;
printf ("%d ", opt[p][q]);
print(p, opt[p][q] - 1);
print(opt[p][q] + 1, q);
}
int main() {
cin >> n;
memset(f, -1, sizeof(f));
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
f[i][i] = a[i];
f[i][i - 1] = 1;
opt[i][i] = i;
}
for (int len = 2; len <= n; len ++) {
for (int i = 1; i <= n; i ++) {
int j = i + len - 1;
for (int k = i; k <= j; k ++) {
if (f[i][j] < f[i][k - 1] * f[k + 1][j] + a[k]) {
f[i][j] = f[i][k - 1] * f[k + 1][j] + a[k];
opt[i][j] = k;
}
}
}
}
cout << f[1][n] << endl;
print(1, n);
return 0;
}