控制动态编程解决方案的组合方面

时间:2018-02-14 11:34:53

标签: python algorithm dynamic-programming combinatorics memoization

我正在探索动态规划设计方法如何与问题的潜在组合属性相关联。

为此,我正在查看硬币兑换问题的规范实例:让S = [d_1, d_2, ..., d_m]n > 0成为请求金额。除了n中的元素之外,我们可以使用多少种方式添加S

如果我们按照动态编程方法为这个问题设计一个允许多项式复杂度的解决方案的算法,我们首先要看问题以及它与小问题的关系。更简单的子问题。这将产生递归关系,描述根据其相关子问题的解决方案表示问题的归纳步骤。然后,我们可以实施 memoization 技术或制表技术,以便在自上而下底部有效地实现此递归关系分别是方式。

递归关系可能如下(Python 3.6语法和基于0的索引):

def C(S, m, n):
    if n < 0:
        return 0
    if n == 0:
        return 1
    if m <= 0:
        return 0
    count_wout_high_coin = C(S, m - 1, n)
    count_with_high_coin = C(S, m, n - S[m - 1])
    return count_wout_high_coin + count_with_high_coin

但是,在绘制子问题DAG时,可以看到任何实现此递归关系的基于DP的算法都会产生正确数量的解决方案,但忽略了顺序。

例如,对于S = [1, 2, 6]n = 6,可以确定以下方式(假设订单事项):

  1. 1 + 1 + 1 + 1 + 1 + 1
  2. 2 + 1 + 1 + 1 + 1
  3. 1 + 2 + 1 + 1 + 1
  4. 1 + 1 + 2 + 1 + 1
  5. 1 + 1 + 1 + 2 + 1
  6. 1 + 1 + 1 + 1 + 2
  7. 2 + 2 + 1 + 1
  8. 1 + 2 + 2 + 1
  9. 1 + 1 + 2 + 2
  10. 2 + 1 + 2 + 1
  11. 1 + 2 + 1 + 2
  12. 2 + 1 + 1 + 2
  13. 2 + 2 + 2
  14. 6
  15. 确定顺序并不重要,我们可以计算以下解决方案:

    1. 1 + 1 + 1 + 1 + 1 + 1
    2. 2 + 1 + 1 + 1 + 1
    3. 2 + 2 + 1 + 1
    4. 2 + 2 + 2
    5. 6
    6. 从动态编程的角度来看问题解决方案时,我该如何控制订单?具体来说,我怎么能写函数:

      • count_with_order()
      • count_wout_order()

      对订单问题的需求是否意味着选择通过动态规划方法进行修剪回溯?

1 个答案:

答案 0 :(得分:1)

每个问题都是特殊的,尽管可能会有一些问题可以组合在一起。对于您的特定示例,可以通过考虑n的解决方案数量等于每个可实现的较低数量可实现的解决方案总数(即{{1}来实现订单重要的计数(递归或制表)。 1}}为每个面额。

Python代码:

n - coin