python 动态规划 数塔_【朝夕的ACM笔记】动态规划-数塔问题

数塔问题相关

前言

数塔问题,又称数字三角形、数字金字塔问题,源自于1994年的IOI赛题。数塔问题是多维动态规划问题中一类常见且重要的题型,其变种众多,难度遍布从低到高,掌握该类型题目的算法思维,对于攻克许多多维动态规划的问题有很大帮助。

一、数塔问题原型

1.1 问题描述

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5有一个r行的数塔,数塔上有若干数字。问从数塔的最高点到底部,在所有的路径中,经过的数字的和最大为多少?

如上图,是一个5行的数塔,其中7—3—8—7—5的路径经过数字和最大,为30。

1.2 解法思路

面对数塔问题,使用贪心算法显然是行不通的,比如给的样例,如果使用贪心算法,那选择的路径应当是7—8—1—7—5,其经过数字和只有28,并不是最大。而用深搜DFS很容易算出时间复杂度为

(因为每个数字都有向左下和右下两种选择),行数一多必定超时。

所以,数塔问题需要使用动态规划算法。

①我们可以从上往下遍历。

可以发现,要想经过一个数字,只能从左上角或右上角的数字往下到达。

所以显然,经过任一数字A时,路径所经过的数字最大和——是这个数字A左上方的数字B以及右上方的数字C两个数字中,所能达到的数字最大和中较大的那一个,再加上该数字A。

故状态转移方程为:

其中i,j表示行数和列数,dp表示储存的最大和,num表示位置上的数字。

表示左上角,

表示右上角。

以样例来说明:在经过第三行的数字1时,我们先看它左上角的数字3和右上角的数字8其能达到的最大和。3显然只有7—3一条路径,故最大和是10;8显然也只有7—8一条路径,其最大和是15;两者中较大的是15,故经过1所能达到的最大和是15+1=16。

这样一步步向下遍历,最后经过每一个位置所能达到的最大和都求出来了,只要从最底下的一行里寻找最大值并输出即可。

②我们也可以从下往上遍历。

一条路径不管是从上往下走还是从下往上走,其经过的数字和都是一样的,所以这题完全可以变成求——从最底层到最高点所经过的最大数字和。

其写法与顺序遍历是一样的,只是状态转移时,变成从该数字的左下角和右下角来取max了。逆序遍历的写法相比于顺序遍历优点在于:少了最后一步求最后一行max的过程,可以直接输出最高点所储存的值。

1.3 代码实现

#include #include using namespace std;//这里以顺序遍历为例int num[1005][1005];//用于储存数塔每个位置的数字int dp[1005][1005];//用于储存经过数塔每个位置所能达到的最大和int main()

{

int r;

scanf("%d",&r);//输入数塔行数 for(int i=1;i<=r;i++)

for(int j=1;j<=i;j++)

scanf("%d",&num[i][j]);

//输入数塔数据,注意i和j要从1开始,防止数组越界 for(int i=1;i<=r;i++)//共计r行 for(int j=1;j<=i;j++)//每行有j个数字 dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+num[i][j];

//经过该数字的最大和,为左上角和右上角中的max,再加上该数字 int ans=0;

for(int i=1;i<=r;i++)

ans=max(ans,dp[r][i]);//从最后一行中找到最大数

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值