每日一题13:数字金字塔

题目描述

观察如下数字金字塔。请写一个程序查找从最高点到底部任意点(数字金字塔共有行)结束的路径,使路径经过数字的和最大,每一步只能走到左下方的点或右下方的点。

7

3  8

8  1  0

2  7  4  4

4  5  2  6  5

在如上样例中,7→3→8→7→5的路径产生了所有路径中最大的和7+3+8+7+5=30。

输入格式

第1行输入,表示行数。

之后每行为数字金字塔特定行包含的整数(所有数非负且不大于100)。

输出格式

一行,路径产生的最大的和。

分析

方法1

直接搜索。设二维数组存放数字金字塔中的每个整数,存放最终结果即最大的和。问题要求从最高点按照规则走到最低点的路径的最大权值和,路径起终点固定,走法规则明确,可考虑使用搜索解决问题。

定义无返回类型递归函数   ,其中表示当前已从走到,目前已走路径上的权值和为

时,到达递归出口,如果,则把更新为。当时,未到达递归出口,则向下一行两个位置行走,即递归执行

方法1实际上把所有路径都走了一边,由于每一条路径由步组成,每一步有左右两种选择,因此路径总数为,时间复杂度为太大会超时。

方法2

方法1之所以会超时,是因为进行了重复搜索。当多次来到同一点时,可以直接调用来到这一点时的路径权值和,避免重复搜索。该方法称为记忆化搜索。

定义  表示从出发到终点的路径最大权值和,所以为所求答案。计算时考虑第一步是向左还是向右,就把所有路径分成两大类。

第一步向左的路径:从出发到终点的这类路径就被分成两个部分,先从,要使得这种情况的路径权值和最大,第二部分从到终点的路径权值和也要最大,所以这一部分可以表示成。综上所述,第一步向左的路径最大权值和为

第一步向右的路径:从出发到终点的这类路径就被分成两个部分,先从,要使得这种情况的路径权值和最大,第二部分从到终点的路径权值和也要最大,所以这一部分可以表示成。综上所述,第一步向左的路径最大权值和为。分析方法与如上分类同理。

同样为了避免重复搜索,开设全局数组记录从每个点出发到终点路径的最大权值和,一开始全部初始化为-1表示未被计算过(即未到达过这一点)。在计算时,首先查询,如果,说明之前已被计算过,直接返回即可,否则计算出的值并存储在中,以便下次调用。

由于对于每个合法的都计算且仅计算过一次,而且是在内完成的,因此时间复杂度为,不超时。

方法3

方法3使用动态规划完成。方法2的记忆化搜索本质上与动态规划高度相似。

确定状态

题目要求从出发到底层路径的最大权值和,路径是由各个点串联而成,路径起点固定,终点和中间点相对不固定。因此定义表示从出发到达的路径最大权值和,并设······

确定状态转移方程和边界条件

不考虑的每一步是如何走的,只考虑最后一步是如何走的,根据最后一步是向左还是向右分成如下两种情况:

最后一步向左的路径:最后一步是从,此类路径被分割成两部分,第一部分是从走到,第二部分是从走到,要计算此类路径的最大权值和,必须用到第一部分的最大权值和,此部分问题的性质与一样,就是,第二部分就是。两部分相加即得到此类路径的最大权值和为

最后一步向右的路径: 最后一步是从,此类路径被分割成两部分,第一部分是从走到,第二部分是从走到,要计算此类路径的最大权值和,必须用到第一部分的最大权值和,此部分问题的性质与一样,就是,第二部分就是。两部分相加即得到此类路径的最大权值和为

的计算需要求出如上两种情况的最大值。综上所述,得到状态转移方程为

与递归关系式需要终止条件一样,这里也需要对边界进行处理防止无限递归。计算时需要用到,随着递归的深入,最终都要用到的计算不可再用状态转移方程,而是应直接赋予一个特值

所以根据上述得到边界条件为

现在分析一下此动态规划的正确性,分析该解法是否满足使用动态规划的两个前提:

最优化原理:这个在分析状态转移方程时已经较为透彻,明显符合最优化原理。

无后效性:状态转移方程中,只会关心的值,计算时可能有多种不同的决策对应着最优值,选哪种决策对计算的决策没有影响,符合无后效性。

实现

由于状态转移方程就是递归关系式,边界条件就是递归终止条件,所以可以用递归来完成。递归存在重复调用,利用记忆化搜索可以解决这一点。记忆化搜索实现比较简单,且不会计算无用状态,但递归也会受到"栈的大小"和"递推+回归执行方式"的约束,另外记忆化实现调用状态的顺序是按照实际需求展开,没有大局规划,不利于进一步优化。

一种迭代法与分析边界条件相类似,计算用到状态,这两个元素都在的上一行。也就是说,要计算第行的状态的值,必须先把第行的状态的值计算出来,再利用状态转移方程。可以先把赋值为,再从第2行开始按照行递增的顺序计算出每一行的有效状态。

对于题目所给样例,计算的结果如下表所示:

样例对应的

1 2 3 4 5
1 7 / / / /
2 10 15 / / /
3 18 16 15 / /
4 20 25 20 19 /
5 24 30 27 26 24

该动态规划时间复杂度为,不会超时。

代码

方法1

#include<bits/stdc++.h>
using namespace std;
int a[1005][1005],n,ans;
void dfs(int x,int y,int cur){if(x==n){ans=max(ans,cur);return;}dfs(x+1,y,cur+a[x+1][y]);dfs(x+1,y+1,cur+a[x+1][y+1]);
}
int main(){cin>>n;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)cin>>a[i][j];dfs(1,1,a[1][1]);cout<<ans;return 0;
}

方法2

#include<bits/stdc++.h>
using namespace std;
int a[1005][1005],f[1005][1005],n;
int dfs(int x,int y){if(f[x][y]==-1)f[x][y]=(x==n?a[x][y]:a[x][y]+max(dfs(x+1,y),dfs(x+1,y+1)));return f[x][y];
}
int main(){memset(f,-1,sizeof(f));cin>>n;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)cin>>a[i][j];dfs(1,1);cout<<f[1][1];return 0;
}

方法3

#include<bits/stdc++.h>
using namespace std;
int a[1005][1005],f[1005][1005],n,ans;
int main(){cin>>n;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)cin>>a[i][j];f[1][1]=a[1][1];for(int i=2;i<=n;i++)for(int j=1;j<=i;j++)f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j]);for(int i=1;i<=n;i++)ans=max(ans,f[n][i]);cout<<ans;return 0;
}

C++ 每日一题13:数字金字塔相关推荐

  1. 【寒假每日一题】数字三角形(个人练习)详细题解+推导证明(第二天)

    文章目录 前言 题目 详细题解 写法1 O ( n 2 ) O(n^2) O(n2) 推导证明 写法2 O ( n 2 ) O(n^2) O(n2) 推导证明 举一反三 总结 前言 昨天真是人生中奇葩 ...

  2. JS 每日一题 #13

    这是一个从基础到进阶的JavaScript问题列表,题源来自Github的 JavaScriptQuestions,有32K star. 前端开发博客 打算每日更新一道题,一起来学习打卡吧.如果觉得内 ...

  3. 5位数的数字黑洞是多少_每日一题[491]数字黑洞--Kaprekar常数

    定义$\overline{abc}$是一个三位数,其中各数位上的数字$a,b,c\in \{ 0,1,2,3,4,5,6,7,8,9 \}$且不全相同.定义如下运算$f$:把$\overline{ab ...

  4. LeetCode每日一题: 缺失数字(No.268)

    题目:缺失数字 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数. 复制代码 示例: 输入: [3,0,1] 输出: 2输入: [9,6 ...

  5. C语言每日一题——查找数字

    在一组"有序"数组中查找某个数字,如果找到返回其下表,如果没有找到,输出"不存在". 一,遍历查找 就是将所有数都遍历一遍 找是否存在该数字如果存在返回下标 具 ...

  6. C语言每日一题——数字金字塔

    如果有同学问你,"你会用代码打印出,数字金字塔吗?" 如果你阅读了这篇文章你将,会十分自信的去告诉他,这都小意思. //数子金字塔 //1//01(0代表空格 方便演示) //12 ...

  7. 北妈每日一题:JS从无序乱码找我要的数字!

    点击上方"前端你别闹",关注并星标 喜欢我的都关注我了 北妈每日一题 我需要整齐排列 问题1:有这样一串杂乱无章的数据: [dahsidoai 213907;a oas198jdo ...

  8. 电动力学每日一题 2021/10/13 用Fourier变换法计算静止电荷产生的电场

    电动力学每日一题 2021/10/13 用Fourier变换法计算静止电荷产生的电场 静止点电荷 具有均匀线密度的静止电荷产生的电场 具有均匀面密度的静止电荷产生的电场 用Fourier变换法计算电场 ...

  9. 【解题报告】Leecode 423. 从英文中重建数字——Leecode每日一题系列

    今天是坚持每日一题打卡的第二十五天 题目链接:https://leetcode-cn.com/problems/reconstruct-original-digits-from-english/ 题解 ...

最新文章

  1. yii2嵌入微信公众号支付
  2. golang runtime.findrunnable epoll_wait lock 占用CPU 过多排查
  3. panel.setLayout(null);
  4. SimpleDateFormat详解
  5. 【转】C/C++的64位整型 不同编译器间的比较
  6. python 结巴分词学习
  7. wi7计算机桌面删除,如何删除win7系统桌面IE图标|win7删除桌面IE图标的方法
  8. ECSHOP整合第三方登录,ECSHOP第三方QQ登录插件,ECSHOP第三方新浪微博登录插件,ECSHOP第三方支付宝登插件,ECSHOP淘宝登陆插件,ECSHOP第三方MSN登录
  9. 软件测试工程师未来十年的职业规划
  10. 计算机显示找不到gpedit,Win7系统gpedit.msc找不到的解决方法
  11. Kubernetes pod的生命周期
  12. GNU C++ 智能指针6-- 解析_Sp_counted_inplace类
  13. Redis设置过期时间为当月月底-----自动计算
  14. 计算机台式硬件排名,CPU天梯图2019年1月最新版 一月台式电脑处理器排名
  15. 亿佰特LoRaWAN入网TTN并订阅MQTT消息
  16. 可以分屏的软件_mac必备软件
  17. 南京印象之出租车司机
  18. 单例模式和多例模式详解
  19. java的字典序排序_java字典序排序
  20. 工业机器人 郝卫东_六自由度机器人焊接轨迹研究

热门文章

  1. 【机器学习 吴恩达】2022课程笔记(持续更新)
  2. 【思想感悟】拨开云雾见天日
  3. PS制作CSS精灵图
  4. Zeppelin使用JDBC连接MySQL
  5. linux下最全抓包命令使用方式学习和拓展
  6. ICMP、IGMP、RARP、ARP以及Tcp/Ip等一些含义说明(软考必考)
  7. Day27_GUI编程
  8. VB编程:利用循环嵌套求1000以内的完数-18
  9. Python运维开发(CMDB资产管理系统)--环境部署(上)
  10. 数字电子基础课程设计——基于74LS90的电子时钟,可实现校准时分秒以及清零