加分二叉树---区间dp

第二天叫醒我的不是闹钟,是梦想!

题目描述
科技忽略了过程就是魔法,魔法展示了过程就是科技。例如,在魔法世界彪炳史册的艾萨克·牛顿爵士,就被称为“最初的科学家,最后的炼金术士”。魔法世界的所谓魔法,其本质就是科技,只不过因为在远古时代发生的几次战乱,导致相当数量尖端科技理论的遗失和残缺,使得人们只知道如何使用科技却无法解释其原理,只好统称为魔法而已。所以魔法世界的科技树在宇宙各种文明的发展中,可以抽象的看成一颗奇怪的具有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行:一个整数,为最高加分(结果不会超过4000 000 000)。 第2行:n个用空格隔开的整数,为该树的前序遍历。(行尾有一个空格)
样例输入 Copy
10
5 4 8 9 19 2 1 40 20 22
样例输出 Copy
839701
7 4 2 1 3 5 6 9 8 10

//区间dp。
f[l,r]表示所有中序遍历是[L,R]这一段的二叉树的集合
假设k为根节点,那么左子树就是f[l,k-1],右子树就是f[k+1,r],加分就是
f[l,k-1]*f[k+1,r]*w[k];

怎么前序遍历输出呢?
用g[l,r]存f[l,r]最大根节点


#include<bits/stdc++.h>
using namespace std;
const int N=110;
int w[N];
int f[N][N];
int g[N][N];
void print(int l,int r)
{
  if(l>r) return ;
  int root=g[l][r];
  cout<<root<<" ";
  print(l,root-1);
  print(root+1,r);
}
int main()
{
    int n;
    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=len+l-1;
        if(len==1)  //叶子结点
        {
          f[l][r]=w[l];
          g[l][r]=l;
        }
        else
        {
          for(int k=l;k<=r;k++)
          {
            int left=k==l ? 1:f[l][k-1];
            int right=k==r ? 1:f[k+1][r];
            int score=left*right+w[k];
            if(f[l][r]<score)
            {
              f[l][r]=score;
              g[l][r]=k;
            }
          }
        }
      }
      cout<<f[1][n]<<endl;
      print(1,n);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值