一个 n n n个节点的二叉树,每个节点都有一个分数,每颗子树也有分数
每颗子树的分数计算方法为:
s u b t r e e 的 左 子 树 的 加 分 × s u b t r e e s u b t r e e 的 右 子 树 的 加 分 + s u b t r e e s u b t r e e 的 根 的 分 数 。 subtree的左子树的加分× subtreesubtree的右子树的加分+subtreesubtree的根的分数。 subtree的左子树的加分×subtreesubtree的右子树的加分+subtreesubtree的根的分数。
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树
试求一棵符合中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,…,n) (1,2,3,…,n)且加分最高的二叉树 t r e e tree tree。要求输出;
(1) t r e e tree tree的最高加分
(2) t r e e tree tree的前序遍历
我们用 d p [ m ] [ i ] [ j ] dp[m][i][j] dp[m][i][j]来表示一颗以 m m m为根,子树为 i − j i-j i−j的树的最大得分, s u m [ l ] [ r ] sum[l][r] sum[l][r]来代表子树节点是 i − j i-j i−j的子树的最大得分
那么 d p [ m ] [ i ] [ j ] = m a x ( d p [ m ] [ i ] [ j ] , ( s u m [ i ] [ m − 1 ] ∗ s u m [ m + 1 ] [ j ] ) ∗ a [ m ] ) , s u m [ i ] [ j ] = m a x ( d p [ m ] [ i ] [ j ] , s u m [ i ] [ j ] ) dp[m][i][j]=max(dp[m][i][j],(sum[i][m-1]*sum[m+1][j]) * a[m]),sum[i][j]=max(dp[m][i][j],sum[i][j]) dp[m][i][j]=max(dp[m][i][j],(sum[i][m−1]∗sum[m+1][j])∗a[m]),sum[i][j]=max(dp[m][i][j],sum[i][j]),
这样状态转移就写完了, 后面就是递归输出这棵树了,每次找区间的最大值作为根节点,然后向左向右递归
void First(int l, int r) {
int Max = 0, u = -1;
for (int i = l; i <= r; i ++) {
if(Max < dp[i][l][r]) {
Max = dp[i][l][r];
u = i;
}
}
if(l == 1 && r == n) printf("%lld\n", Max);
printf("%d ", u);
if(u - 1 >= l) First(l, u-1);
if(u + 1 <= r) First(u+1, r);
}
#include
using namespace std;
#define LL long long
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int Mod = 1e9 + 7;
const double eps = 1e-8;
typedef pair<int, int> psi;
void fre() {
if(freopen("洛谷P1040.txt", "r", stdin) == NULL)
system("touch 洛谷P1040.txt");
freopen("洛谷P1040.txt", "r", stdin);
}
LL dp[40][40][40], a[40], sum[40][40];
int n;
void First(int l, int r) {
int Max = 0, u = -1;
for (int i = l; i <= r; i ++) {
if(Max < dp[i][l][r]) {
Max = dp[i][l][r];
u = i;
}
}
if(l == 1 && r == n) printf("%lld\n", Max);
printf("%d ", u);
if(u - 1 >= l) First(l, u-1);
if(u + 1 <= r) First(u+1, r);
}
int main(int argc, char *args[]) {
fre();
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
memset(dp, 0, sizeof(dp));
for (int i = 0; i <= n; i ++)
for (int j = 0; j <= n; j ++)
sum[i][j] = 1;
for (int i = 1; i <= n; i ++) dp[i][i][i] = sum[i][i] = a[i];
for (int k = 1; k <= n-1; k ++) {
for (int l = 1; l + k <= n; l ++) {
for (int m = l; m <= l + k; m ++) {
dp[m][l][l+k] = max(dp[m][l][l+k], (sum[l][m-1] * sum[m+1][l+k]) + a[m]);
sum[l][l+k] = max(sum[l][l+k], dp[m][l][l+k]);
}
}
}
First(1, n);
return 0;
}