题目链接:http://acm.swust.edu.cn/problem/360/
Time limit(ms): 1000 Memory limit(kb): 65535
Description
设一个n个节点的二叉树tree的中序遍历为(l,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的前序遍历
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 |
解题思路:区间dp,注意在更新dp值时,标记下根节点方便输出先序遍历,今天才晓得memset居然不能将数组值置为1,汗~~~
代码如下:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 50, inf = -0x7fffffff; 8 int n,ptr, vi[maxn], dp[maxn][maxn], root[maxn][maxn]; 9 //若根节点的下标是k,则左端点的是k-1,右端点是k+1; 10 void PreOrder(int vi, int y){ 11 if (root[vi][y]){ 12 if (ptr++) cout << ‘ ‘; 13 cout << root[vi][y]; 14 PreOrder(vi, root[vi][y] - 1); 15 PreOrder(root[vi][y] + 1, y); 16 } 17 } 18 19 int main(){ 20 //freopen("360-加分二叉树.in","r",stdin); 21 //freopen("360-加分二叉树.out", "w", stdout); 22 while (cin >> n){ 23 for (int i = 0; i <= n; i++) 24 for (int j = 0; j <= n; j++) 25 dp[i][j] = 1; 26 for (int i = 1; i <= n; i++){ 27 cin >> vi[i]; 28 dp[i][i] = vi[i]; 29 root[i][i] = i; 30 } 31 for (int r = 1; r <= n; r++){ 32 for (int i = 1; i <= n - r; i++){ 33 int j = i + r, tmp = inf; 34 for (int k = i; k < j; k++){ 35 if (tmp < (dp[i][k - 1] * dp[k + 1][j] + vi[k])){ 36 tmp = dp[i][k - 1] * dp[k + 1][j] + vi[k]; 37 root[i][j] = k; 38 } 39 } 40 dp[i][j] = tmp; 41 } 42 } 43 cout << dp[1][n] << endl; 44 ptr = 0; 45 PreOrder(1, n); 46 cout << endl; 47 } 48 //fclose(stdin); fclose(stdout); 49 return 0; 50 }
时间: 2024-12-17 06:14:13