vijos1100 加分二叉树 ( dp)

dp[l,r] =max(dp[l,k]*dp[k+1,r] + G[k] )  l<=k<r

用一个G[l][r] 的数组记录路径 , 在打印的时候也用递归

 

描述

设一个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的前序遍历

格式

输入格式

第1行:一个整数n(n<30),为节点个数。

第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。

输出格式

第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。

第2行:n个用空格隔开的整数,为该树的前序遍历。

样例1

样例输入1[复制]

5
5 7 1 2 10

样例输出1[复制]

145
3 1 2 4 5

限制

每个测试点1s

来源

NOIP2003第三题

 

 

代码:

vijos1100 加分二叉树 ( dp)
 1 #include <iostream>
 2 using namespace std;
 3 #define LL long long
 4 int n;
 5 int mid[50];
 6 int first[50][50];
 7 int dp[50][50];
 8 int dfs(int L,int R)
 9 {
10         int &d = dp[L][R];
11         if(d)return d;
12         if( R-L ==1)
13         {
14             first[L][R] = L;
15             return d = mid[L];
16         }
17         if( L == R) return 1;
18 
19         for(int k=L;k<R;k++)
20         {
21             int  g =  dfs( L,k)*dfs(k+1,R) +mid[k];
22             if(  d < g )
23             {
24                 d=g;
25                 first[L][R] = k;
26             }
27         }
28         return d;
29 }
30 void print(int L, int R)
31 {
32     if( L >=R) return;
33 
34     cout<<first[L][R]+1<<" ";
35     print(L,first[L][R]);
36     print(first[L][R]+1,R);
37 
38 }
39 int main()
40 {
41     cin>>n;
42     for(int i=0;i<n;i++)
43     {
44         cin>>mid[i];
45     }
46     cout<<dfs(0,n)<<endl;
47     print(0,n);
48     return 0;
49 }
vijos1100 加分二叉树 ( dp)

 

vijos1100 加分二叉树 ( dp)

上一篇:CNBlog 自定义格式


下一篇:认识javascript中的作用域和上下文