zoukankan      html  css  js  c++  java
  • P1040 加分二叉树 区间dp

      

    题目描述

    设一个nn个节点的二叉树tree的中序遍历为(1,2,3,…,n1,2,3,,n),其中数字1,2,3,…,n1,2,3,,n为节点编号。每个节点都有一个分数(均为正整数),记第ii个节点的分数为di,treedi,tree及它的每个子树都有一个加分,任一棵子树subtreesubtree(也包含treetree本身)的加分计算方法如下:

    subtreesubtree的左子树的加分× subtreesubtree的右子树的加分+subtreesubtree的根的分数。

    若某个子树为空,规定其加分为11,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

    试求一棵符合中序遍历为(1,2,3,…,n1,2,3,,n)且加分最高的二叉树treetree。要求输出;

    (1)treetree的最高加分

    (2)treetree的前序遍历

    输入输出格式

    输入格式:

    11行:11个整数n(n<30)n(n<30),为节点个数。

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

    输出格式:

    11行:11个整数,为最高加分(Ans le 4,000,000,0004,000,000,000)。

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

    输入输出样例

    输入样例#1: 复制
    5
    5 7 1 2 10
    
    输出样例#1: 复制
    145
    3 1 2 4 5


    难以下手 看到是dfs专题一直想着用dfs来解
    这题用区间dp很方便能解
    f(i,j)={1 (i>j) ; 顶点i的分数 (i=j) ; max(f{i,k-1}*f{k+1,j}+顶点i的分数 (i<j) 『k取i~j』)  root[i, j]——顶点i..顶点j所组成的子树达到最大分值时的根编号。当i = j时,root[i, i] := i。
    再根据树来输出
    记忆化dp 
    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);i--)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define pb push_back
    #define fi first
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    ///////////////////////////////////
    #define inf 0x3f3f3f3f
    #define N 100
    int root[N][N];
    LL dp[N][N];
    int n;
    int first;
    LL search1(int L,int R)//区间记忆化dp
    {
        if(L>R)return 1;//说明为一棵空树
        if(dp[L][R]==-1)
        {
            rep(k,L,R)
            {
                LL cnt=search1(L,k-1)*search1(k+1,R)+dp[k][k];
                if(cnt>dp[L][R])
                {
                    dp[L][R]=cnt;
                    root[L][R]=k;
                }
            }
        }
        return dp[L][R];
    }
    
    void print(int L,int R)
    {
        if(L>R)return ;
        if(first)first=0;
        else printf(" ");
        int x=root[L][R];
        printf("%d",x);
        print(L,x-1);
        print(x+1,R);
        return;
    }
    int main()
    {
        RI(n);
        rep(i,1,n)
        rep(j,1,n)
        dp[i][j]=-1;
        rep(i,1,n)
        {
            int x;
            RI(x);
            dp[i][i]=x;//每个顶点的值
            root[i][i]=i;//每个点单独成一棵树 根即为自己
        }
        cout<<search1(1,n)<<endl;
        first=1;
        print(1,n);
    }
    View Code

    非记忆化

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);i--)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define pb push_back
    #define fi first
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    ///////////////////////////////////
    #define inf 0x3f3f3f3f
    #define N 100
    int root[N][N];
    LL dp[N][N];
    int n;
    int first;
    
    void print(int L,int R)
    {
        if(L>R)return ;
        if(first)first=0;
        else printf(" ");
        int x=root[L][R];
        printf("%d",x);
        print(L,x-1);
        print(x+1,R);
        return;
    }
    int main()
    {
        RI(n);
        rep(i,1,n)
        rep(j,1,n)
        dp[i][j]=-1;
        rep(i,1,n)
        {
            int x;
            RI(x);
            dp[i][i]=x;//每个顶点的值
            dp[i][i-1]=1;
            root[i][i]=i;//每个点单独成一棵树 根即为自己
        }
        rep(len,1,n)
        rep(i,1,n)
        {
            int j=i+len;
            if(j<=n)
            rep(k,i,j)
            if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+dp[k][k])
            {
                 dp[i][j]=dp[i][k-1]*dp[k+1][j]+dp[k][k];
                 root[i][j]=k;
            }
        }
        cout<<dp[1][n]<<endl;
        first=1;
        print(1,n);
    }
    View Code

    更加简洁

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,v[39],f[47][47],i,j,k,root[49][49];
    void print(int l,int r){
        if(l>r)return;
        if(l==r){printf("%d ",l);return;}
        printf("%d ",root[l][r]);
        print(l,root[l][r]-1);
        print(root[l][r]+1,r);
    }
    int main() {
        scanf("%d",&n);
        for( i=1; i<=n; i++) scanf("%d",&v[i]);
        for(i=1; i<=n; i++) {f[i][i]=v[i];f[i][i-1]=1;}
        for(i=n; i>=1; i--)
            for(j=i+1; j<=n; j++)
                for(k=i; k<=j; k++) {
                    if(f[i][j]<(f[i][k-1]*f[k+1][j]+f[k][k])) {
                        f[i][j]=f[i][k-1]*f[k+1][j]+f[k][k];
                        root[i][j]=k;
                    }
                }
        printf("%d
    ",f[1][n]);
        print(1,n);
        return 0;
    }
    View Code



  • 相关阅读:
    优秀的云架构师需要学什么技能
    dkh人力资源大数据解决方案整体架构
    大数据hadoop与spark的区别
    hadoop技术入门学习之发行版选择
    大数据开发基础知识需要掌握哪些
    智慧人社政务云平台建设方案架构案例介绍
    [项目机会]citrix 虚拟桌面对于java等高CPU占用率如何解决
    [办公自动化]无法使用江南天安usbkey 无法使用视频网站
    [学习笔记]从0到1
    [办公自动化]目录修改以及插入分页符后行间距自动变宽
  • 原文地址:https://www.cnblogs.com/bxd123/p/10614900.html
Copyright © 2011-2022 走看看