动态更改算法,返回实际使用的硬币列表

时间:2017-06-27 08:20:10

标签: python dynamic-programming coin-change

我正在尝试调整维基百科中的代码:

https://en.wikipedia.org/wiki/Change-making_problem#Implementation

还输出使用的硬币列表,而不仅仅是使用的硬币数量。也就是说,例如:

change_making([6, 8, 12], 52)输出5这是正确的(12+12+12+8+8 = 52)。

问题是我想以这种格式[12, 12, 12, 8, 8]而不仅仅是5获得输出,我不知道该怎么做。

有问题的代码:

def _get_change_making_matrix(set_of_coins, r):
    m = [[0 for _ in range(r + 1)] for _ in range(len(set_of_coins) + 1)]

    for i in range(r + 1):
        m[0][i] = i

    return m


def change_making(coins, n):
    """This function assumes that all coins are available infinitely.

    n is the number that we need to obtain with the fewest number of coins.

    coins is a list or tuple with the available denominations."""

    m = _get_change_making_matrix(coins, n)

    for c in range(1, len(coins) + 1):

        for r in range(1, n + 1):

            # Just use the coin coins[c - 1].
            if coins[c - 1] == r:
                m[c][r] = 1

            # coins[c - 1] cannot be included.
            # We use the previous solution for making r,
            # excluding coins[c - 1].
            elif coins[c - 1] > r:
                m[c][r] = m[c - 1][r]

            # We can use coins[c - 1].
            # We need to decide which one of the following solutions is the best:
            # 1. Using the previous solution for making r (without using coins[c - 1]).
            # 2. Using the previous solution for making r - coins[c - 1] (without using coins[c - 1]) plus this 1 extra coin.
            else:
                m[c][r] = min(m[c - 1][r], 1 + m[c][r - coins[c - 1]])

    return m[-1][-1]

非常感谢任何帮助/建议。

-------------编辑-------------

解决方案(删除了评论):

def _change_making(coins, n):
    m = [[0 for _ in range(n + 1)] for _ in range(len(coins) + 1)]
    for i in range(n + 1):
        m[0][i] = i

    for c in range(1, len(coins) + 1):
        for r in range(1, n + 1):
            if coins[c - 1] == r:
                m[c][r] = 1
            elif coins[c - 1] > r:
                m[c][r] = m[c - 1][r]
            else:
                m[c][r] = min(m[c - 1][r], 1 + m[c][r - coins[c - 1]])

    i = len(coins)
    j = n
    ret = {k: 0 for k in coins}
    while j != 0:
        if m[i][j - coins[i - 1]] == m[i][j] - 1:
            ret[coins[i - 1]] += 1
            j = j - coins[i - 1]
        else:
            i = i - 1

    return ret

要找到最近的 *解决方案:

def change_making(coins, n):
    try:
        return _generate_packing(coins, n)
    except:
        return generate_packing(coins, n + 1)

例如change_making([2, 5], 8)

{2: 2, 5: 1}

因为9是最接近的解决方案。

  • 通过最近我的意思是一种可以满足但高于原始请求的解决方案。例如,如果我们需要返回8英镑的变更而我们没有确切的变化,那么,我们将返回9英镑,因为我们确实有变化。

1 个答案:

答案 0 :(得分:1)

以下是您可以采取的步骤 -

1)从i=len(coins)j=n开始,即数组的末尾(或列表)m

2)现在我们知道如果coins(i-1)仅使用一枚硬币而不是m[i][j],则会选择价值为m[i][j-coins[i-1]]的硬币。

3)如果没有发生这种情况,我们会检查其他硬币(列表中较低指数的硬币)是否符合相同条件。

示例 -

一开始我们有52值,我们已经用你的功能解决了它需要5个硬币。

我们只使用12的第一枚硬币,如果价值40(即52 -12)我们需要4个硬币,同样适用于第2和第3个12值硬币。

但是我们无法使用第四个12硬币作为值4(即16-12)无法使用1个硬币实现。

以下是执行相同操作的代码段(您可以在函数末尾使用而不是使用return语句) -

i=len(coins)
j = n
while(j!=0):
    if m[i][j-coins[i-1]] == m[i][j]-1:
        print(coins[i-1])
        j=j-coins[i-1]
    else:
        i=i-1