【问题标题】:Dynamic change-making algorithm that returns actual list of coins used动态找零算法,返回实际使用的硬币列表
【发布时间】:2017-06-27 08:20:10
【问题描述】:

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

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]

任何帮助/建议将不胜感激。

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

解决方案(移除 cmets):

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 英镑,因为我们确实有找零。

【问题讨论】:

    标签: python dynamic-programming coin-change


    【解决方案1】:

    您可以按照以下步骤操作 -

    1) 以i=len(coins)j=n 开头,即数组(或列表)的结尾m

    2) 现在我们知道,如果 m[i][j] 使用的硬币恰好比 m[i][j-coins[i-1]] 多一个硬币,则选择价值为 coins(i-1) 的硬币。

    3)如果没有发生这种情况,我们会检查其他硬币(列表中较低索引的硬币)是否处于相同状态。

    示例-

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

    仅当价值 40(即 52 -12)我们需要 4 个硬币时,我们才使用 12 的第一个硬币,对于第 2 和第 3 个 12 价值硬币也是如此。

    但我们不能使用第四个 12 硬币作为价值 4(即 16-12)不能使用 1 个硬币来实现。

    这里是代码 sn-p 做同样的事情(你可以在你的函数末尾使用它而不是 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
    

    【讨论】:

    • 谢谢,完美!请问-您将如何调整代码以输出“最接近”的解决方案,例如coins = [6, 8]n = 19。显然,我们不能仅从偶数中创建奇数。但是,我们可以为n = 20 执行6+6+8。在找到可能的解决方案之前,是否有比尝试n += 1change_making([6, 8, 12], n) 更优化的方法?
    • 取决于您需要答案的“接近”原始值的程度。就像只有 1 的差异,你可以 - 1) 创建 m 矩阵直到范围 m[len(coins)][n+1]( 最初是 m[len(coins)][n]) 并在代码中进行必要的调整。 2) 当 sum n 不可能时,比较 m[len(coins)][n+1]m[len(coins)][n-1] (比如 n=18 和 20 最接近)。 3)输出这两个中的最小值。
    • 我正在尝试解决类似的问题,但每种类型的硬币数量是有限的。例如:(1, count: 10), (2, count:5) 等等。所以知道需要改变什么来列出给定值的每种类型的硬币吗?
    猜你喜欢
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    相关资源
    最近更新 更多