动态规划——计数类dp
计数类dp
此类问题一般要我们求解方案数
根据题目描述,可以分为组合数和排列数问题
一般套路是转化为背包问题
组合数类型
一般是先遍历物品再遍历背包,这样才能固定一个顺序
例题
一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 109+7 取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
N = 1010
MOD = int(1e9) + 7
f = [0] * N
n = int(input())
f[0] = 1
for i in range(1, n + 1) :
for j in range(i, n + 1) :
f[j] = (f[j] + f[j - i]) % MOD
print(f[n])
排列数类型
一般先遍历背包再遍历物品,这样背包中的物品才不会只有一个顺序
例题
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
示例 1:
输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
nums 中的所有元素 互不相同
1 <= target <= 1000
N = 210
nums = [0] * N
f = [0] * N
n, m = map(int, input().split())
nums[1 : n + 1] = list(map(int, input().split()))
f[0] = 1
for j in range(0, m + 1) :
for i in range(1, n + 1) :
if j - nums[i] >= 0 :
f[j] += f[j - i]
print(f[m])
总结
计数类dp一般都是转化为0-1背包或者完全背包问题来求解
特别的,当使用完全背包时,先遍历背包还是物品是有考究的。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!