组合的动态编程习语

时间:2010-08-09 20:59:19

标签: algorithm language-agnostic dynamic-programming

考虑一个价值为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习惯用法是什么? (非优雅的解决方案,例如生成所有可能的解决方案并删除重复项不受欢迎)

3 个答案:

答案 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