您的位置:首页 > 其它

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

2017-08-26 15:42 381 查看
NOIP 2003 提高组 复赛 加分二叉树

1.样例1分析是关键:

输入:

5
5 7 1 2 10


输出:

145
3 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]
);

    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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: