动态规划——计数类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背包或者完全背包问题来求解
特别的,当使用完全背包时,先遍历背包还是物品是有考究的。

posted @   chanxe  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示