題目描述
設一個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,爲節點個數。
第2行:n個用空格隔開的整數,爲每個節點的分數(0<分數<100)。
輸出格式
第1行:一個整數,爲最高加分(結果不會超過4,000,000,000)。
第2行:n個用空格隔開的整數,爲該樹的前序遍歷。如果存在多種方案,則輸出字典序最小的方案。
數據範圍
n<30
輸入樣例:
5
5 7 1 2 10
輸出樣例:
145
3 1 2 4 5
思路
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 35;
int f[N][N], g[N][N];
int n;
int w[N];
void dfs(int l, int r)
{
if(l > r) return;
cout << g[l][r] << " ";
dfs(l, g[l][r] - 1);
dfs(g[l][r] + 1, r);
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
cin >> w[i];
for(int len = 1; len <= n; len++)
for(int l = 1; l + len - 1 <= n; l++)
{
int r = l + len - 1;
if(len == 1)
{
f[l][r] = w[l];
g[l][r] = l;
}
else
{
for(int k = l; k <= r; k++)
{
int left, right;
if(k == l)
left = 1;
else left = f[l][k - 1];
if(k == r)
right = 1;
else right = f[k + 1][r];
int sore = left * right + w[k];
if(sore > f[l][r])
{
f[l][r] = sore;
g[l][r] = k;
}
}
}
}
cout << f[1][n] << endl;
dfs(1, n);
return 0;
}