组合的动态编程习语

Yuv*_*dam 3 language-agnostic algorithm dynamic-programming

考虑一下你有一个价值的问题N,你需要计算N使用[1,2,5,10,20,50,100]Dollar账单总计美元的方法.

考虑经典的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 
Run Code Online (Sandbox Code Playgroud)

它不会影响求和部分的顺序.例如,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习惯用法是什么?(不受欢迎的非优雅解决方案,例如生成所有可能的解决方案并删除重复项)

小智 7

不确定任何DP习语,但您可以尝试使用生成函数.

我们需要找到的是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).

你现在可以根据统一根的乘积来对每个因子进行因式分解,用部分分数(这是一个步骤)分割倒数,并找出每个中的x ^ N的系数(其形式为多项式/( xw))并将它们加起来.

你可以在计算统一的根源时做一些DP.


Luk*_*hne 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 
Run Code Online (Sandbox Code Playgroud)

或等效的(可能更具可读性)

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 
Run Code Online (Sandbox Code Playgroud)