1、题目分析
这是蓝书《算法竞赛进阶指南》多重背包的一道例题,硬币为物品,面值为体积,M为背包总容积,我们很容易就分析出这是一个可行性问题而不是一道最优化问题。
这道题我们如果用直接拆分或者二进制拆分的方法做的话都会TLE,但我们如果用单调队列优化是可以AC的,这里给出的是另一种题解。
可行性问题和最优化问题有着本质上的区别,在最优化问题中,我们需要考虑所有的状态有可能这时候不好但转移到下一个阶段就是最优,但可行性问题中只有True和False ,所以我们可以用全局动规,局部贪心的做法让其在阶段 i 时选择尽可能少的 a[i], 这样后面就可以用更多的硬币来拼其他面值,这样一定是最优的,并且让我们省去了一重对 c[i] 的循环,将时间复杂度优化到了O(nm)
这里我们定义一个used数组 used[j] 来记录 f[j]在第 i 阶段为True时,至少需要用多少枚硬币,我们 j 采用完全背包的迭代方式 通过used数组实现多重背包中“物品个数”的限制,代码如下:
代码
import sys
while True:
n,m = map(int, sys.stdin.readline().split())
if n == m and n == 0: break
ls = [0]+list(map(int, sys.stdin.readline().split()))
used, f = [0]*(m+1), [0]*(m+1)
f[0] = 1
for i in range(1, n+1):
for j in range(1, m+1): used[j] = 0
for j in range(ls[i], m+1):
if f[j] == 0 and used[j - ls[i]] < ls[i+n] and f[j-ls[i]]:
f[j] = 1
used[j] = used[j - ls[i]] + 1
ans = 0
for i in range(1,m+1):
ans += f[i]
print(ans)