考虑一个价值为N
的问题,您需要使用N
美元钞票计算总计达[1,2,5,10,20,50,100]
美元的方式。
考虑经典的DP解决方案:
C = [1,2,5,10,20,50,100]
def comb(p):
if p==0:
return 1
c = 0
for x in C:
if x <= p:
c += comb(p-x)
return c
它不会影响求和部分的顺序。例如,comb(4)
将产生5个结果:[1,1,1,1],[2,1,1],[1,2,1],[1,1,2],[2,2]
而实际上有3个结果([2,1,1],[1,2,1],[1,1,2]
都相同)。
计算此问题的DP习惯用法是什么? (非优雅的解决方案,例如生成所有可能的解决方案并删除重复项不受欢迎)
答案 0 :(得分:7)
不确定任何DP惯用语,但您可以尝试使用Generating Functions。
我们需要找到的是
中x ^ N的系数(1 + x + x ^ 2 + ...)(1 + x ^ 5 + x ^ 10 + ...)(1 + x ^ 10 + x ^ 20 + ...)......( 1 + x ^ 100 + x ^ 200 + ...)
(1次出现次数* 1次+ 5次出现次数* 5 + ......)
与
的倒数相同(1-X)(1-x ^ 5)(1-x ^ 10)(1-x ^ 20)(1-x ^ 50)(1-x ^ 100)。
现在,您可以根据统一根的乘积对每个因子进行分解,用Partial Fractions(这是一步)分割倒数,并在每个中找出x ^ N的系数(这将是形式为多项式/(xw))并将它们加起来。
你可以在计算统一的根源时做一些DP。
答案 1 :(得分:5)
你不应该每次都从开始,但最大的时候你是从每个深度来的。 这意味着您必须传递两个参数,即开始和剩余总数。
C = [1,5,10,20,50,100]
def comb(p,start=0):
if p==0:
return 1
c = 0
for i,x in enumerate(C[start:]):
if x <= p:
c += comb(p-x,i+start)
return c
或同等(可能更具可读性)
C = [1,5,10,20,50,100]
def comb(p,start=0):
if p==0:
return 1
c = 0
for i in range(start,len(C)):
x=C[i]
if x <= p:
c += comb(p-x,i)
return c
答案 2 :(得分:1)
术语:你要找的是“整数分区” 在预先标记的部分(你应该替换标题中的“组合”)。 忽略问题的“动态编程”部分,例程 对于你的问题,在第16章的第一节给出 (fxtbook的“整数分区”,第399页),在线上 http://www.jjj.de/fxt/#fxtbook