动态编程(使用确切数量的硬币进行精确更改)

时间:2015-11-08 05:33:08

标签: algorithm recursion dynamic-programming coin-change

我有无限的4种类型的硬币:[1,5,25,50]。 如何选择 EXACT 48个硬币进行1美元的改变?(以任何一种有效的方式)

我知道如何递归地解决这个问题,但是可以使用DP来解决它吗?怎么样?谢谢!

2 个答案:

答案 0 :(得分:1)

让我们想制作n cents,我们会获得每个S = { S1, S2, S3, .. Sm }硬币的无限供应。

动态规划方法:

要计算解决方案的总数,我们可以将所有设置解决方案划分为两组

  1. 不包含mth coin (or Sm)的解决方案。
  2. 包含at least one Sm
  3. 的解决方案

    count(S[], m, n)成为计算解决方案数量的函数,然后它可以写成count(S[], m-1, n)count(S[], m, n-Sm) sum

    如此表述为

    count(n,m) = count(n, m-1) + count(n- sm, m)
    

    以下基本情况:

    1. count(n,m) =1, n=0,一个解决方案 - 我们没有钱,只有一种方法可以解决问题 - 选择不改变硬币,或者更准确地说,选择硬币更换0

    2. count(n,m) =0, n<0,没有解决方案 - 负金额

    3. count(n,m) =1, n>=1, m<=0,没有解决方案 - 我们有钱,但没有可用的更改

答案 1 :(得分:1)

可能的解决方案可能如下(Haskell):

change d coins | null coins = []
               | d==0 = []
               | d>=coin = coin:change (d-coin) coins           
               | otherwise = change d (tail coins) where
        coin = head coins

请注意:

  1. 鉴于解决方案假定硬币列表已被排序
  2. 无法更改给定值的情况未处理 - 我只是没有包括检查,只是展示了这个想法
  3. 要更改的输入值为美分
  4. 以下是一些结果:

    *Main> change 100 [50, 25, 5, 1]
    [50,50]
    *Main> change 99 [50, 25, 5, 1]
    [50,25,5,5,5,5,1,1,1,1]
    *Main> change 75 [50, 25, 5, 1]
    [50,25]
    

    如果您对解决方案中使用的硬币数量有限制:

    exactChange d coins n
        | d==0 && n==0 = [[]]
        | d>0 && n==0 = []
        | d==0 && n>0 = []
        | null coins = []
        | d>=coin = useFirstCoinSolutions ++ skipFirstCoinSolutions
        | otherwise = skipFirstCoinSolutions where
        coin = head coins
        rest = tail coins
        useFirstCoinSolutions = map (\x->coin:x) $ exactChange (d-coin) coins (n-1)
        skipFirstCoinSolutions = exactChange d rest n
    

    这给出了以下结果:

    *Main> exactChange 100 [50, 25, 5, 1] 48
    [[25,25,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[25,5,5,5,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[5,5,5,5,5,5,5,5,5,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
    

    因此,它提供了所有可能的解决方案,用精确的48个硬币改变100分

    解释

    1. 第一个条件d == 0&amp;&amp; n == 0定义了找到的单个解决方案:我们没有变更金额,零金币留在变更中;
    2. 接下来的三个条件定义无法找到解决方案;
    3. d&gt; =硬币这意味着给定金额高于硬币组中的第一枚硬币所以我们必须选择:进行解决方案搜索第一枚硬币或继续硬币集合
    4. 对于第一枚硬币高于金额的情况,我们只能在不使用第一枚硬币的情况下进行