1. 程式人生 > >【luogu1040】加分二叉樹

【luogu1040】加分二叉樹

num sign 中序 計算方法 個數 整數 一個 -m 輸入輸出

題目描述

設一個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

 1 #include <iostream>
 2 using namespace std;
 3 int n, num[40], root[40][40];
 4 unsigned long long dp[40][40];
 5 void
print(int i, int j) { 6 if (i == j) 7 cout << i << ; 8 else if (i < j) { 9 cout << root[i][j] << ; 10 print(i, root[i][j] - 1); 11 print(root[i][j] + 1, j); 12 } 13 } 14 int main() { 15 cin >> n; 16 for (int i = 1; i <= n; i++)
17 cin >> num[i]; 18 // f(i,j)=max{f(i,k-1)*f(k+1,j)+num[k]} (i<=k<=j) 19 for (int i = 1; i <= n; i++) 20 dp[i][i] = num[i]; 21 for (int len = 2; len <= n; len++) { 22 for (int i = 1, j = len; j <= n; i++, j++) { 23 for (int k = i; k <= j; k++) { 24 int multiple = 1; 25 if (k != i) 26 multiple *= dp[i][k - 1]; 27 if (k != j) 28 multiple *= dp[k + 1][j]; 29 if (dp[i][j] < num[k] + multiple) { 30 dp[i][j] = num[k] + multiple; 31 root[i][j] = k; 32 } 33 } 34 } 35 } 36 cout << dp[1][n] << endl; 37 print(1, n); 38 return 0; 39 }

【luogu1040】加分二叉樹