NOIP 2003 提高组 复赛 加分二叉树

来源:互联网 发布:java available的用法 编辑:程序博客网 时间:2024/05/20 16:32

NOIP 2003 提高组 复赛 加分二叉树

1.样例1分析是关键:

输入:

55 7 1 2 10

输出:

1453 1 2 4 5

1 2 3 4 5 中序遍历

3 1 2 4 5 前序遍历

分析可得二叉树如下图:

    3
  /   \
 1     4
  \     \
   2     5

3的左子树计算1*7+5=12

3的右子树计算1*10+2=12

总加分12*12+1=145

2.关于该题,此文介绍得比较详细http://www.cnblogs.com/sdjl/articles/1273759.html

3.http://blog.csdn.net/senyelicone/article/details/52602151此文代码写得够短。

4.http://www.cnblogs.com/Renyi-Fan/p/7421129.html代码注释写得不错。

5.n=3数据分析处理过程如下:


6.可以开始代码编写。

7.调试代码花了一定时间,样例终于通过了,提交AC。2017-8-29

8.动态规划AC代码如下:

//P1040 加分二叉树
#include <stdio.h>
int a[35],root[35][35];//f[i][j]中序遍历i-j最大分数 root[i][j] i-j的根 
long long f[35][35];
void preorder(int left,int right){//先序遍历  传入的参数是 中序遍历的 左边界 与右边界
    if(left>right)return;
    printf("%d ",root[left][right]);//中序遍历特征,根节点左侧为左子树,根节点右侧为右子树 
    preorder(left,root[left][right]-1);
    preorder(root[left][right]+1,right); 
}
int main(){
    int n,i,j,k;
    scanf("%d",&n);
    for(i=0;i<=n;i++)//2 此处写成 for(i=1;i<=n;i++) 查了好久 
        for(j=0;j<=n;j++)//2 此处写成  for(j=1;j<=n;j++) 查了好久 
            f[i][j]=1;//i>j f[i][j]值为1 
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]),f[i][i]=a[i],root[i][i]=i;//1 低级错误 ,此处写成 f[i][i]=root[i][i]=a[i];
    for(i=n;i>=1;i--)//只有i=n这种方式才能做到f[i][j]从小区间计算到大区间,并且之后的大区间能完全用到前面算好的小区间 
        for(j=i+1;j<=n;j++)
            for(k=i;k<=j;k++)//k从小到大,能保证之后的先序遍历在多解的情况下,按字典序输出
                if(f[i][j]<f[i][k-1]*f[k+1][j]+a[k])
                    f[i][j]=f[i][k-1]*f[k+1][j]+a[k],root[i][j]=k;
    printf("%lld\n",f[1][n]);
    preorder(1,n);
    return 0;
}

9.//P1040 加分二叉树
//记忆化搜索 2017-8-29 21:30 AC
#include <stdio.h>
#include <string.h>
int a[35],root[35][35];
long long f[35][35];
long long dfs(int left,int right){
    int k;
    long long t;
    if(f[left][right])return f[left][right];
    if(left==right)return a[left];
    if(left>right)return 1;
    for(k=left;k<=right;k++){
        t=dfs(left,k-1)*dfs(k+1,right)+a[k];
        if(f[left][right]<t){
            f[left][right]=t;
            root[left][right]=k;
        }
    }
    return f[left][right];//1 漏了该句,很致命
}
void preorder(int left,int right){
    if(left>right)return;
    if(left==right){printf("%d ",left);return;}//2 漏了该句 if(left==right){printf("%d ",left);return;}
    printf("%d ",root[left][right]);
    preorder(left,root[left][right]-1);
    preorder(root[left][right]+1,right);
}
int main(){
    int n,i;
    memset(f,0,sizeof(f));
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    printf("%lld\n",dfs(1,n));
    preorder(1,n);
    return 0;
}