【问题标题】:Minimum coin change: reconstruct solution from this algorithm最小硬币变化:从该算法重建解决方案
【发布时间】:2015-06-08 15:27:12
【问题描述】:

我已经在 Python 中为经典的最小硬币找零puzzle 实现了动态编程solution,并且对我的简短易懂(对我而言)解决方案感到非常满意:

def memoize(fcn):
    cache = {}
    def decorated(d, p):
        if p not in cache:
            cache[p] = fcn(d, p)
        return cache[p]
    return decorated

@memoize
def mc(d, p):
    if p in d: return 1
    cands = [n for n in d if n < p]
    if not cands: return 10**20
    return 1 + min ([mc(d, p-d_i) for d_i in cands])

In [101]:
d = [1, 5, 10, 25, 21]
p = 63
mc(d, p)
Out[101]:
3

但现在我想我会尝试并实际退出最佳解决方案中使用的硬币。 IE。对于上述情况,我想输出 21 + 21 + 21。

但是,根据我的程序制定,我认为没有办法轻松做到这一点。我必须跟踪整个解决方案树,然后根据减去的更改递归地向上移动节点以到达该特定节点。

那么,有没有一种简单的方法可以为此修改我的解决方案?谢谢

【问题讨论】:

  • 请使用更具描述性的变量名称。 d 是什么? p 是什么?另请注意,您仅使用p 进行记忆,这可能会影响某些事情。
  • 我添加了输入/输出示例以使变量名称明显......

标签: python-2.7 dynamic-programming


【解决方案1】:

试试这个:

def memoize(fcn, cache = {}):
    def decorated(d, p):
        if p not in cache:
            cache[p] = fcn(d, p)
        return cache[p]
    return decorated

@memoize
def mc(d, p):
    if p in d:
        return (1, [p])

    cands = [n for n in d if n < p]

    if not cands:
        return (10**20, [])

    d_i, pair = min(
        [(d_i, mc(d, p-d_i)) for d_i in cands],
        key=lambda e: e[1][0]
    )

    return (1 + pair[0], pair[1] + [d_i])

在您的示例中,它将返回一对 (3, [21, 21, 21])。

这是一个快速的解决方案。如果您需要集成或分发它,我建议您使用 OOP 样式,如下所示:

class MinimumCoinChangeSolver(object):
    def __init__(self):
        self.coins = None
        self.count = None
        self.__cache = {}


    def solve(self, coins, amount):
        self.reset_cache()
        self.coins = self.__recursive_solve(coins, amount)
        self.count = len(self.coins)


    def reset_cache(self):
        self.__cache = {}


    def __recursive_solve(self, coins, amount):
        # try to find solution in cache
        if amount in self.__cache:
            solution = self.__cache[amount]

        else:
            # if given amount equals to one of teh coins, return list which contains corresponding coin (it equals to amount)
            if amount in coins:
                solution = [amount]

            else:
                # find coins candidates, they are less then given amount
                coins_cands = filter(
                    lambda coin: coin < amount,
                    coins
                )

                # if there is no coins candidate, return no coins (it is an empty list on coins)
                if not coins_cands:
                    solution = []

                else:
                    # try to use every coin among the candidates, and recursively find list of coins in every case
                    solutions = map(
                        lambda coin: self.__recursive_solve(coins, amount - coin),
                        coins_cands
                    )

                    # ignoring empty solutions
                    solutions = filter(
                        lambda sol: bool(sol),
                        solutions
                    )

                    # if there is no non-empty solutons, return empty list
                    if not solutions:
                        solution = []

                    else:
                        # choose the solution which has minimum number of coins
                        min_solution = min(
                            solutions,
                            key=lambda sol: len(sol)
                        )

                        # remember corresponding coin
                        coin = amount - sum(min_solution)

                        # solution
                        solution = min_solution + [coin]

        # save solution in cache
        self.__cache[amount] = solution

        # return
        return solution



if __name__ == "__main__":
    solver = MinimumCoinChangeSolver()
    solver.solve([1, 5, 10, 25, 21], 63)
    print solver.coins
    print solver.count

【讨论】:

  • 我还注意到,如果我连续多次调用我的 mc 函数,我会得到一些奇怪的结果,因为每次函数调用后记忆缓存都不会被清除。你也有解决这个问题的快速提示吗?再次感谢
  • 我已经编辑了 memoize 功能来解决你的问题。
  • 谢谢。但这似乎不起作用。如果在 memoize 函数之外声明缓存并在每个函数调用之前写入 cache={} ,它就可以工作。但这不是一个很好的解决方法
  • 我正在努力理解你的解决方案,我永远不会想出这样的东西。我觉得非常好。如果你有时间,如果你在程序中添加一些你的思考过程会很好......谢谢
猜你喜欢
  • 2015-09-02
  • 2022-07-01
  • 2018-10-07
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多