最小硬币变化:从该算法重构解决方案
Minimum coin change: reconstruct solution from this algorithm
我已经在 Python 中实现了动态规划 solution for the classic minimum coin change puzzle 并且对我的简短易懂(对我而言)的解决方案感到非常满意:
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.
但是,根据我的程序制定,我看不出有什么办法可以轻松做到这一点。我将不得不跟踪整个解决方案树,然后根据减去的更改递归向上移动节点以到达该特定节点。
那么,有没有一种简单的方法可以为此修改我的解决方案?谢谢
试试这个:
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])
在您的示例中,它将 return 一对 (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
我已经在 Python 中实现了动态规划 solution for the classic minimum coin change puzzle 并且对我的简短易懂(对我而言)的解决方案感到非常满意:
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.
但是,根据我的程序制定,我看不出有什么办法可以轻松做到这一点。我将不得不跟踪整个解决方案树,然后根据减去的更改递归向上移动节点以到达该特定节点。
那么,有没有一种简单的方法可以为此修改我的解决方案?谢谢
试试这个:
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])
在您的示例中,它将 return 一对 (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