包子的旷野吧 关注:9贴子:209
  • 3回复贴,共1

[程序] 加分二叉树 [Vijos 1100]

只看楼主收藏回复

描述 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 Format  
  第1行:一个整数n(n<30),为节点个数。
 第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
 

输出格式 Output Format  
  第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
 第2行:n个用空格隔开的整数,为该树的前序遍历。


样例输入 Sample Input   
5
5 7 1 2 10 
   
   
样例输出 Sample Output   
145
3 1 2 4 5
   
   
时间限制 Time Limitation  
  每个测试点1s 
   
   
来源 Source  
  NOIP2003第三题 


1楼2007-08-13 09:29回复
    明显的动态规划题目

    状态:
    f[i][j] 段[i,j]所能得到的最大分数

    转移:
    max(f[i][k-1]*f[k+1][j]+v[k]) i<=k<=j


    f[1][n]

    时间
    O(n^3)

    空间
    O(n^2)


    2楼2007-08-13 09:32
    回复
      /*
       加分二叉树
       Program by Alex
       13-08-07 09:43
      */

      #include <stdio.h>

      #define maxn 30+1

      int d[maxn][maxn],root[maxn][maxn];

      int v[maxn];

      int n;

      int f(int a,int b,int c){
       if(d[a][b]) return d[a][b];
       if(b<a) return 1;
       if(a==b){
       root[a][b]=a;
       return v[a];
       }
       int i,now,best=0,tl,tr;
       for(i=a;i<=b;i++){
       now=f(a,i-1,c+1)*f(i+1,b,c+1)+v[i];
       if(now>best){
       best=now;
       root[a][b]=i;
       }
       }
       d[a][b]=best;
       return best;
      }

      void display(int a,int b){
       printf("%d ",root[a][b]);
       if(a<root[a][b]) display(a,root[a][b]-1);
       if(b>root[a][b]) display(root[a][b]+1,b);
      }

      int main(){
       freopen("vijos1100.in","r",stdin);
       freopen("vijos1100.out","w",stdout);
       scanf("%d",&n);
       int i;
       for(i=1;i<=n;i++)
       scanf("%d",&v[i]);
       printf("%d\n",f(1,n,1));
       i=1;
       display(1,n);
       return 0;
      }


      3楼2007-08-13 09:32
      回复
        大哥你做错了OK?
        #include<iostream>
        #include<cstring>
        using namespace std;
        //int max_nodes=40;
        int n;
        long best[40][40];
        int root[40][40];
        bool first;
        void visit(int i,int j)//当前序遍历为1,2,3,4,5。。。时,中序遍历的求法。 
        {
             if(i>j)
               return ;
             if(first)
              first=false;
             else 
               cout<<" ";
             cout<<root[i][j];
             visit(i,root[i][j]-1);
             visit(root[i][j]+1,j);
                 

        long Search_Best(int l,int r)
        {
              int i;
              long now;
              if(l>r) return 1;
              else
               {
                   if(best[l][r]==-1)
                     {
                         for(i=l;i<=r;i++)
                           {
                               now=Search_Best(l,i-1)*Search_Best(i+1,r)+best[i][i];
                               if(now>best[l][r])
                                {
                                    best[l][r]=now;
                                    root[l][r]=i;
                                }    
                           }    
                     }    
                return best[l][r];
               }    
        }    
        int main()
        {
                
             freopen("binary.in5","r",stdin);
             freopen("out3.txt","w",stdout); 
            while( cin>>n)
            {
             memset(best,-1,sizeof(best));
             memset(root,-1,sizeof(root));
             for(int i=1;i<=n;i++)
               { cin>>best[i][i];
                  root[i][i]=i;
                }
             cout<<Search_Best(1,n)<<endl;
             first=true;
             visit(1,n);
             cout<<endl<<endl;    
            }      
             return 0;
        }


        4楼2009-08-22 08:55
        回复