NOIP 2003 提高组 复赛 加分二叉树
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.****.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;
}