首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【算法】动态规划专题① ——线性DP python

  • 25-02-15 07:21
  • 4399
  • 14030
blog.csdn.net

目录

  • 引入
  • 简单实现
  • 稍加变形
  • 举一反三
  • 实战演练
  • 总结


引入


楼梯有个台阶,每次可以一步上1阶或2阶。一共有多少种不同的上楼方法?

怎么去思考?
假设就只有1个台阶,走法只有:1
只有2台阶: 1+1,2
只有3台阶: 1+2, 1+1+1 ,2+1
只有4台阶: 1+1+2 ,2+2 , 1+2+1 ,1+1+1+1,2+1+1
不难观察到
3台阶的走法可以表示为1台阶的走法再+2,2台阶的走法+1
4台阶的走法可以表示为2台阶的走法再+2,3台阶的走法+1
自然递推出:
n台阶的走法可以表示为n-2台阶的走法再+2,n-1台阶的走法+1


解决步骤:
1.定义状态:
设dp[n]表示到达第n级台阶的不同方法总数。
2.状态转移方程:
因为每次只能走1步或2步,所以到达第n级台阶的方法数等于到达第(n-1)级台阶的方法数加上到达第(n-2)级台阶的方法数。
即dp[n]=dp[n-1]+dp[n-2]。
3.初始化:
当n=0时,没有台阶,认为有一种方法(什么都不做),因此dp[0]=1。
当n=1时,只有一种方法,即直接走上第一级台阶,所以dp[1]=1。
4.计算顺序:从低到高依次计算每一级台阶的方法数直到n。



简单实现


跳台阶 https://www.acwing.com/problem/content/823/

一个楼梯共有 n n n 级台阶,每次可以走一级或者两级,问从第 0 0 0 级台阶走到第 n n n 级台阶一共有多少种方案。

输入格式

共一行,包含一个整数 n n n。

输出格式

共一行,包含一个整数,表示方案数。

数据范围

1 ≤ N ≤ 15 1\leq N\leq15 1≤N≤15

输入样例:

5
  • 1

输出样例:

8
  • 1

代码如下(示例):
n = int(input())
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
for i in range(2, n + 1):
    dp[i] = dp[i - 1] + dp[i - 2]
print(dp[n])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7


稍加变形


哎,就是玩 给你几个楼梯弄坏

破损的楼梯 https://www.lanqiao.cn/problems/3367/learning/?page=1&first_category_id=1&problem_id=3367

在这里插入图片描述

思路:

用vis数组标记不能走的台阶即可


题解code:

mod = 1000000007
n, m = map(int, input().split())
a = list(map(int, input().split()))
dp = [0] * (n + 1)
dp[0] = 1
vis = [0] * (n + 1)
for i in a:
    vis[i] = 1
for i in range(1, n + 1):
    if vis[i] == 0:
        dp[i] = (dp[i - 1] + dp[i - 2]) % mod
print(dp[n])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


举一反三


每次可以走一级或者两级或者三级,一共有多少种方案呢?
测试链接 https://www.acwing.com/problem/content/3646/


每次可以向上迈 1∼K 级台阶,答案又是多少呢?
在这里我们给出1-k级台阶的解法


台阶问题 https://www.luogu.com.cn/problem/P1192

题目描述

有 N N N 级台阶,你一开始在底部,每次可以向上迈 1 ∼ K 1\sim K 1∼K 级台阶,问到达第 N N N 级台阶有多少种不同方式。

输入格式

两个正整数 N , K N,K N,K。

输出格式

一个正整数 a n s ( m o d 100003 ) ans\pmod{100003} ans(mod100003),为到达第 N N N 级台阶的不同方式数。

样例输入

5 2
  • 1

样例输出

8
  • 1

提示

  • 对于 20 % 20\% 20% 的数据, 1 ≤ N ≤ 10 1\leq N\leq10 1≤N≤10, 1 ≤ K ≤ 3 1\leq K\leq3 1≤K≤3;
  • 对于 40 % 40\% 40% 的数据, 1 ≤ N ≤ 1000 1\leq N\leq1000 1≤N≤1000;
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100000 1\leq N\leq100000 1≤N≤100000, 1 ≤ K ≤ 100 1\leq K\leq100 1≤K≤100。

思路分析:

结合上面所学,不难得出:
dp[ i i i] = dp[ i i i - 1] + dp[ i i i - 2] + ······ +dp[ i i i - k k k]
当然,这是 i ≥ k i\geq k i≥k的情况
对于 i < k i< k i<k:
dp[ i i i] = dp[ i i i - 1] + dp[ i i i - 2] + ······ +dp[0]

题解code

mod = 100003

n, k = map(int, input().split())
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
for i in range(2, n + 1):
    res = 0
    for j in range(min(i, k) + 1):
        res += dp[i - j]
    dp[i] = res % mod
print(dp[n])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


结合前缀和能更快得出答案
什么?还不会前缀和?
点此跳转 超细致讲解


code:

mod = 100003
n, k = map(int, input().split())
dp = [0] * (n + 1)
dp[0] = 1
pre_sum = [0] * (n + 2)
pre_sum[1] = 1
for i in range(1, n + 1):
    if i <= k:
        dp[i] = pre_sum[i] % mod
    else:
        dp[i] = (pre_sum[i] - pre_sum[i - k]) % mod
    pre_sum[i + 1] = (pre_sum[i] + dp[i]) % mod
print(dp[n])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13



实战演练


安全序列 https://www.lanqiao.cn/problems/3423/learning/?page=1&first_category_id=1&problem_id=3423

在这里插入图片描述

思路分析:

只有一个空位,那么只有 {0},{1}两种放法
两个空位,那么在上面的基础上放0或者隔k个0放1
{0,0},{1,0},{0,1}
三个空位,直接放0,或者隔k个0放1
{0,0,0} ,{1,0,0},{0,1,0}, {0,0,1}
四个空位,继续递推
{0,0,0,0} {1,0,0,0} {0,1,0,0} {0,0,1,0} {0,0,0,1} {1,0,0,1}
得到递推公式:
写出状态转移方程:
dp[ i i i] = dp[ i i i-1](后面直接放0)+ dp[ i i i- k k k-1](隔k个0后放1)


题解code:

mod = 1000000007
n, k = map(int, input().split())
dp = [0] * (n + 1)
dp[0] = 1
for i in range(1, n + 1):
    if i - k - 1 >= 0:
        dp[i] = (dp[i - k - 1] + dp[i - 1]) % mod
    else:
        dp[i] = (1 + dp[i - 1]) % mod
print(dp[n])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


总结


线性动态规划(Linear Dynamic Programming, 简称线性DP)是一种动态规划的类型,它主要处理具有线性结构的问题。
在这种问题中,通常会有一个或多个序列作为输入,而解决这些问题的目标是找到满足某些条件的最优解。
线性DP问题的特点是可以将问题分解为若干个子问题,每个子问题仅涉及原问题的一个连续子序列,并且这些子问题之间存在重叠和递推关系。

本篇博客从台阶问题入手,逐步复杂化,帮助更好地理解一维线性DP


END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢

注:本文转载自blog.csdn.net的查理零世的文章"https://blog.csdn.net/2401_87245677/article/details/145400246"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top