【笔记】一维动态规划DP

动态规划DP

动态规划用于解决具有重叠子问题、最优子结构特征的问题。

重叠子问题:子问题是原问题的小版本

最优子结构:大问题的最优解包含小问题的最优解,通过小问题可以推导出大问题

无后效性:“未来与过去无关”,只需要考虑当下如何走到下一步,直接利用结果计算即可,最优子结构满足无后效性。

DP解题步骤

  • 拆分子问题
  • 确定状态:确定状态就是确定问题需要的几个维度的已知变量。一般格式为“前n个x为m的最大价值/最小价值/方案数”
  • 状态转移方程:状态(子问题)之间是如何转移,即一个状态由哪几个状态转移来或者状态可以转移到哪些状态上。
  • 实现:按照循环、记忆化搜索等方程来求解最终状态(答案)

例子1

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

原问题:n个台阶的上楼方案数

  • 子问题:n-1个台阶的上楼方案数、n-2个台阶的上楼方案数……
  • 最优子结构:子问题的最优解能否推出原问题的最优解
  • 确定状态:dp[i]表示前i个空位的放置方案数
  • 状态转移方程:要走到第n级台阶,要么从n-1一步走过去,要么从n-2一步走过去。因此,n个台阶的上楼方案数=n-1个台阶的上楼方案数+n-2个台阶的上楼方案数dp[n]=dp[n-1]+dp[n-2]
  • 实现:for循环实现
"""
台阶编号:到达这个台阶的最大方案数
1:1
2:1+1,2
3:1+1+1,2+1,1+2
......
dp[n]=dp[n-1]+dp[n-2]
dp[1]=1
dp[2]=2
"""
n=int(input())
dp=[0]*(n+1)
dp[1]=1
dp[2]=2
for i in range(3,n+1):
    dp[i]=dp[i-1]+dp[i-2]
print(dp[n])

lanqiao3367 破损的楼梯

题目描述

共有N级台阶,从第0级出发,每次可以迈1阶或者2阶,但是楼梯上的第a1、a2、a3…共M级台阶已经坏了,不能踩上去。

问想要到达楼梯的顶端但不踩破损的台阶,有多少种方案?
由于方案数很大,故输出其对 10 e 9 + 7 10e^9+7 10e9+7取模的结果。

输入格式

第一行:两个整数N,M

第二行:包含M个正整数,表示坏掉的台阶编号

输出格式

输出一个整数

解题思路

这题和上面的例题的差别在于多出了坏掉的台阶,用一个数组vis[n]来 标记坏掉的台阶。
via[i]==1表示第i个台阶坏掉了
via[i]==0表示第i个台阶没有坏

via[i]==1,我们不能踩这个台阶,那么对于第i+1个台阶的方案数就不包含dp[i-1]只有dp[i-2],初始化的时候,dp[i-1]为0,dp[i]=dp[i-2],dp[i+1]=dp[i]+dp[i-1]=dp[i-2]+dp[i-1],所以可以直接continue当遇到via[i]==1

代码
n,m=map(int,input().split())
a=list(map(int,input().split()))
dp=[0]*(n+1)
vis=[0]*(n+1)
for i in a:
    vis[i]=1
dp[0]=1
dp[1]=1-vis[1]
for i in range(2,n+1):
    if vis[i]==1:
        continue
    dp[i]=(dp[i-1]+dp[i-2])%1000000007
print(dp[n]) 

lanqiao3423 安全序列

题目描述

在一条直线上的n个空位放置若干个油桶,每2个油桶之间需间隔k个空位,有多少种放油桶的方式?

输出结果对 10 e 9 + 7 10e^9+7 10e9+7取模

输入格式

第一行:两个正整数n,k

输出格式

输出1个整数,表示方案数对 10 e 9 + 7 10e^9+7 10e9+7取模

解题思路

状态:dp[i]表示前i个空位的放置方案数

状态转移:dp[i]考虑两种情况

第i个空位不放油桶:从dp[i-1]转移

第i个空位放置油桶:从dp[i-k-1]转移

dp[i]=dp[i-1]+(i-k-1>=0?)dp[i-k-1]

代码
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]=(dp[i-1]+1)%mod
print(dp[n]) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值