加分二叉树【题目链接】

感觉我超废


这道题当时压根就不会qwq(我倒是挺适合写rand的qwq)

对于暴力的做法:

  1. 输入数据,定义数组men[i][i]=v[i](输入的第二行);
  2. dfs:
    1. dfs 1—n,首先是几个临界状态:
      1. 当左或右子树为空,即L>R(use L and R replace l and r to be clear)时,返回1
      2. 当L==R时,显然它的分数为它本身,所以return d[L] or d[R]
      3. 还有一个小优化,就是当我们之前已经算过某一段[L,R]时,可以直接拿来取用,即if(mem[l][r]>0)return mem[l][r];

优化的效果:优化前:优化后:效果还是很明显的;

4.然后枚举每个点做这棵子树的根(for循环)这里为了一会输出前序遍历,所以要开数组root[i][j]记录每一段的根是什么;

    前序遍历:前序遍历:先遍历根节点,然后左侧结点,右侧结点(根左右);(插一  句,对于三种顺序的遍历,我们可以这样理解:前序遍历,根在三个字的最前面(根左右);中序遍历,根在左右之间(左 根右);后序遍历,根在左右之后(左右根))因此我们的输出如下:
    1. 先判断L==R?输出L or R:继续;因为在dfs时我们并没有记录L==R时的root值(直接return 了)
    2. 判断输出解的范围,如果L>R显然接下来的输出都是无效的,直接return;
    3. 可以开始输出根root了,输出root[L][R]之后,再递归的输出左子树和右子树(先左后右)

以上就是暴力DFS的思路,以下是代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,v[],mem[][],root[][];
int dfs(int l,int r){
if(mem[l][r]>)return mem[l][r];//当这个点已经被计算过时,直接返回
if(l==r)return v[l];//当只有一个点时,它的值就为本身
if(r<l)return ;//当出现左右颠倒的情况,也就是空子树,加分为1
for(int i=l;i<=r;i++){//分别枚举每个点做子树的根
int p=dfs(l,i-)*dfs(i+,r)/*左子树的值×右子树的值*/+mem[i][i]/*+根结点的值*/;
if(p>mem[l][r]){
mem[l][r]=p;/*求最大值*/root[l][r]=i/*记录路径用来前序遍历*/;
}
}
return mem[l][r];
}
void print(int l,int r){//前序遍历
if(r<l)return;
if(l==r){printf("%d ",l);return;}
printf("%d ",root[l][r]);
print(l,root[l][r]-);
print(root[l][r]+,r);
}
int main(){
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&v[i]),mem[i][i]=v[i];
printf("%d\n",dfs(,n));
print(,n);
return ;
}

对于被称之为正解的做法:

区间dp的做法:

  1. 数组dp[i][j],表示区间[i,j)内的最高加分;
  2. 几种情况:
    1. 对于以一个点建子树,dp[i][i+1](因为是开区间,所以后面要+1)就是对应的输入的加分
    2. 对于以2~n个点建子树,需要一套for循环进行区间dp,最后的答案是dp[1][n+1];区间dp如下:

第一层for循环l:枚举以几个点建子树,可以是2~n;

第二层for循环i:枚举一个区间,需满足i+l<=n+1(举个例子:n=5,以两个点建子树时,i的取值分别为1,2,3,4,相应的区间为[1,2],[2,3],[3,4],[4,5])

第三层for循环k:枚举楼上划分出的区间内以哪个点为根,计算加分,记录其中的最大值(小注意:还要开一个数组用来前序遍历,遍历和dfs的思想是一样的,记录的话也一样,这里用w数组);

样例:

#include <iostream>
using namespace std;
int n;
int d[];
long long dp[][]; //dp[i][j] -> answer in [i,j)
int w[][];
void dfs(int l, int r)
{
cout << w[l][r] << ' ';
if (w[l][r] > l)
dfs(l, w[l][r]);
if (w[l][r] + < r)
dfs(w[l][r] + , r);
}
int main()
{
cin >> n;
for (int i = ; i <= n; i++)
cin >> dp[i][i + ], dp[i][i] = , w[i][i + ] = i;
for (int l = ; l <= n; l++)
{
for (int i = ; i + l <= n + ; i++)
{
int j = i + l;
for (int k = i; k < j; k++)
{
if (dp[i][k] * dp[k + ][j] + dp[k][k + ] > dp[i][j])
{
dp[i][j] = dp[i][k] * dp[k + ][j] + dp[k][k + ];
w[i][j] = k;
}
}
}
}
cout << dp[][n + ] << endl;
dfs(, n + );
}

end-

【6.10校内test】T3 加分二叉树的更多相关文章

  1. CODEVS1090 加分二叉树

    codevs1090 加分二叉树 2003年NOIP全国联赛提高组 题目描述 Description 设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点 ...

  2. NOIP2003加分二叉树[树 区间DP]

    题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都 ...

  3. Vijos 1100 加分二叉树

    题目 1100 加分二叉树 2003年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB   题目描述 Description 设一个n个节点的二叉树tree的中序遍历为( ...

  4. CJOJ 1010【NOIP2003】加分二叉树 / Luogu 1040 加分二叉树(树型动态规划)

    CJOJ 1010[NOIP2003]加分二叉树 / Luogu 1040 加分二叉树(树型动态规划) Description 设 一个 n 个节点的二叉树 tree 的中序遍历为( 1,2,3,-, ...

  5. P1040 加分二叉树

    转自:(http://www.cnblogs.com/geek-007/p/7197439.html) 经典例题:加分二叉树(Luogu 1040) 设一个 n 个节点的二叉树 tree 的中序遍历为 ...

  6. 洛谷P1040 加分二叉树(树形dp)

    加分二叉树 时间限制: 1 Sec  内存限制: 125 MB提交: 11  解决: 7 题目描述 设一个n个节点的二叉树tree的中序遍历为(l,2,3,...,n),其中数字1,2,3,...,n ...

  7. 【洛谷】P1040 加分二叉树

    [洛谷]P1040 加分二叉树 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数 ...

  8. [洛谷P1040] 加分二叉树

    洛谷题目链接:加分二叉树 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,-,n),其中数字1,2,3,-,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di ...

  9. 洛谷P1040 加分二叉树(区间dp)

    P1040 加分二叉树 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di, ...

随机推荐

  1. 阿里云移动研发平台 EMAS 助力银行业打造测试中台,提升发版效能

    随着移动互联网的发展,手机银行凭借低成本.操作简单.不受时间空间约束等优势,正逐步替代传统的网银交易方式.越来越多的银行开始了“业务移动化”转型之路,“手机APP”已经成为企业价值传递和关系维护的关键 ...

  2. 分组统计 over(partition by

    sum( CASE WHEN ISNULL(b.zl, 0) = 0 THEN C.LLZL ELSE b.zl END * c.pccd * b.sl) over(partition by b.dj ...

  3. vscode匹配括号插件

    给大家推荐一个vscode匹配括号的插件: Bracket Pair Colorizer.超级好用哦

  4. 【python学习之五】自定义函数实现用 Python 发送电子邮件

    前言 之前论坛里有人发过关于发送邮件的帖子,设计器也有关于发送邮件的控件.我这里再次重复,希望能有帮到大家的地方. 信息准备 发送邮件前必须准备好一些基本信息,例如发件人邮箱地址.发件人邮箱密码.收件 ...

  5. springboot(六) Maven打包引入本地jar包

       springboot Maven打包引入本地jar包 最近在做项目的时候,有一些jar包不存在maven的依赖库中,所以需要自己引入本地jar包来达到需求,那么我们该如何去将本地的jar包引入s ...

  6. Spring Boot教程(二十三)使用Swagger2构建强大的RESTful API文档(2)

    添加文档内容 在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容.如下所示,我们通 ...

  7. Win7,win10(部分机型) 安装appscan9.0.3.10(可升级)实操流程

    Win10部分机型不能很好的兼容appscan,建议使用者用win7系统安装appscan 写于:2018.12.2 IBM Security AppScan Standard 可通过自动执行应用安全 ...

  8. python中类的设计问题(一些高级问题探讨,函数重载,伪私有,工厂模式,类方法等)

    从这里再次体现了python语言强大的灵活性.某些在高级语言中看似不严谨需要尽量避免的地方在python中都是允许的. 比如: (1),异常可以用来处理错误 (2),方法,类也都可以视为对象. (3) ...

  9. hibernate中的@GeneratedValue与@GenericGenerator

    1.GeneratedValue与GenericGenerator的区别 @GeneratorValue注解----JPA通用策略生成器 @GenericGenerator注解----自定义主键生成策 ...

  10. metrics+spring+influxdb

    https://www.cnblogs.com/lixyu/p/9337055.html