这个问题和这里问的一样。
给定一个硬币列表,它们的值(c1,c2,c3,... cj,...),以及总和i。找出硬币总数为i的最小数量(我们可以根据需要使用一种类型的硬币),或者报告不可能以总和为S的方式选择硬币。
我昨天刚刚被介绍到动态编程,我试图为它编写一个代码。
# Optimal substructure: C[i] = 1 + min_j(C[i-cj])
cdict = {}
def C(i, coins):
if i <= 0:
return 0
if i in cdict:
return cdict[i]
else:
answer = 1 + min([C(i - cj, coins) for cj in coins])
cdict[i] = answer
return answer
这里,C[i]是货币量“i”的最优解。可用的硬币有{c1,c2,…,cj,…}对于这个程序,我增加了递归限制,以避免最大递归深度超过错误。但是,这个程序只给出了一些正确的答案,当一个解决方案不可能时,它并不表明这一点。
我的代码有什么问题,如何更正?
这里有一个有趣的方法。有点像黑客,但这就是为什么它很有趣。
import math
def find_change(coins, value):
coins = sorted(coins, reverse=True)
coin_dict = {}
for c in coins:
if value % c == 0:
coin_dict[c] = value / c
return coin_dict
else:
coin_dict[c] = math.trunc(value/ float(c))
value -= (c * coin_dict[c])
coins = [1, 5, 10, 25]
answer = find_change(coins, 69)
print answer
[OUT]: {25: 2, 10: 1, 5: 1, 1: 4}
下面是带有边缘大小写保护的注释的相同解决方案
import math
def find_change(coins, value):
'''
:param coins: List of the value of each coin [25, 10, 5, 1]
:param value: the value you want to find the change for ie; 69 cents
:return: a change dictionary where the key is the coin, and the value is how many times it is used in finding the minimum change
'''
change_dict = {} # CREATE OUR CHANGE DICT, THIS IS A DICT OF THE COINS WE ARE RETURNING, A COIN PURSE
coins = sorted(coins, reverse=True) # SORT COINS SO WE START LOOP WITH BIGGEST COIN VALUE
for c in coins:
for d in coins: # THIS LOOP WAS ADDED BY A SMART STUDENT: IE IN THE CASE OF IF THERE IS A 7cent COIN AND YOU ARE LOOKING FOR CHANGE FOR 14 CENTS, WITHOUT THIS D FOR LOOP IT WILL RETURN 10: 1, 1: 4
if (d != 1) & (value % d == 0):
change_dict[d] = value / d
return change_dict
if value % c == 0: # IF THE VALUE DIVIDED BY THE COIN HAS NO REMAINDER, # ie, if there is no remainder, all the neccessary change has been given # PLACE THE NUMBER OF TIMES THAT COIN IS USED IN THE change_dict # YOU ARE FINISHED NOW RETURN THE change_dict
change_dict[c] = value / c
return change_dict
else:
change_dict[c] = math.trunc(value/ float(c)) # PLACE THAT NUMBER INTO OUR coin_dict # DIVIDE THE VALUE BY THE COIN, THEN GET JUST THE WHOLE NUMBER # IE 69 / 25.0 = 2.76 # math.trunc(2.76) == 2 # AND THAT IS HOW MANY TIMES IT WILL EVENLY GO INTO THE VALUE,
amount = (c * change_dict[c]) # NOW TAKE THE NUMBER OF COINS YOU HAVE IN YOUR UPDATE THE VALUE BY SUBTRACTING THE c * TIME NUMBER OF TIMES IT WAS USED # AMOUNT IS HOW MUCH CHANGE HAS BEEN PUT INTO THE CHANGE DICT ON THIS LOOP # FOR THE CASE OF 69, YOU GIVE 2 25CENT COINS, SO 2 * 25 = 50, 19 = 69 - 50
value = value - amount # NOW, UPDATE YOUR VALUE, SO THE NEXT TIME IT GOES INTO THIS LOOP, IT WILL BE LOOKING FOR THE MIN CHANGE FOR 19 CENTS...
coins = [1, 5, 10, 25]
answer = find_change(coins, 69)
print answer
[OUT]: {25: 2, 10: 1, 5: 1, 1: 4}
edge_case_coins = [1, 7, 10, 25]
edge_case_answer = find_change(coins, 14)
print edge_case_answer
[OUT]: {7: 2}
正如注释所说,当i
cdict = {}
def C(i, coins):
if i == 0:
return 0
if i < 0:
return 1e100 # Return infinity in ideally
if i in cdict:
return cdict[i]
else:
answer = 1 + min([C(i - cj, coins) for cj in coins])
cdict[i] = answer
return answer
现在,只要函数返回1e100,就意味着解决方案是不可能的。
例如:
$ python2 coins.py 13555 1 5 9
1507 coins
$ python2 coins.py 139 1 5 9
19 coins
$ python2 coins.py 139 5 9
19 coins
$ python2 coins.py 13977 5 9
1553 coins
$ python2 coins.py 13977 9
1553 coins
$ python2 coins.py 139772 9
1e+100 coins
与用法:
python2 coins.py <amount> <coin1> <coin2> ...
这是一个很好的算法问题,但是说实话,我不认为你的实现是正确的,或者可能是我不理解你的函数的输入/输出,为此我道歉。
这是您的实现的修改版本。
def C(i, coins, cdict = None):
if cdict == None:
cdict = {}
if i <= 0:
cdict[i] = 0
return cdict[i]
elif i in cdict:
return cdict[i]
elif i in coins:
cdict[i] = 1
return cdict[i]
else:
min = 0
for cj in coins:
result = C(i - cj, coins)
if result != 0:
if min == 0 or (result + 1) < min:
min = 1 + result
cdict[i] = min
return cdict[i]
这是我试图解决一个类似的问题,但这次返回一个硬币列表。我最初从一个递归算法开始,它接受一个总和和和一个硬币列表,如果找不到这样的配置,它可以返回一个最小硬币数的列表,或者返回一个无。
def get_min_coin_configuration(sum = None, coins = None):
if sum in coins: # if sum in coins, nothing to do but return.
return [sum]
elif max(coins) > sum: # if the largest coin is greater then the sum, there's nothing we can do.
return None
else: # check for each coin, keep track of the minimun configuration, then return it.
min_length = None
min_configuration = None
for coin in coins:
results = get_min_coin_configuration(sum = sum - coin, coins = coins)
if results != None:
if min_length == None or (1 + len(results)) < len(min_configuration):
min_configuration = [coin] + results
min_length = len(min_configuration)
return min_configuration
现在让我们看看是否可以通过使用动态编程(我称之为缓存)来改进它。
def get_min_coin_configuration(sum = None, coins = None, cache = None):
if cache == None: # this is quite crucial if its in the definition its presistent ...
cache = {}
if sum in cache:
return cache[sum]
elif sum in coins: # if sum in coins, nothing to do but return.
cache[sum] = [sum]
return cache[sum]
elif max(coins) > sum: # if the largest coin is greater then the sum, there's nothing we can do.
cache[sum] = None
return cache[sum]
else: # check for each coin, keep track of the minimun configuration, then return it.
min_length = None
min_configuration = None
for coin in coins:
results = get_min_coin_configuration(sum = sum - coin, coins = coins, cache = cache)
if results != None:
if min_length == None or (1 + len(results)) < len(min_configuration):
min_configuration = [coin] + results
min_length = len(min_configuration)
cache[sum] = min_configuration
return cache[sum]
现在让我们运行一些测试。
assert all([ get_min_coin_configuration(**test[0]) == test[1] for test in
[({'sum':25, 'coins':[1, 5, 10]}, [5, 10, 10]),
({'sum':153, 'coins':[1, 5, 10, 50]}, [1, 1, 1, 50, 50, 50]),
({'sum':100, 'coins':[1, 5, 10, 25]}, [25, 25, 25, 25]),
({'sum':123, 'coins':[5, 10, 25]}, None),
({'sum':100, 'coins':[1,5,25,100]}, [100])] ])
假设这些测试不够健壮,您也可以这样做。
import random
random_sum = random.randint(10**3, 10**4)
result = get_min_coin_configuration(sum = random_sum, coins = random.sample(range(10**3), 200))
assert sum(result) == random_sum
有可能没有这样的硬币组合等于我们的随机总和,但我相信这不太可能。。。
我确信有更好的实现,我试图强调可读性而不是性能。祝你好运
更新的以前的代码有一个小错误,它假设检查最小硬币而不是最大硬币,重新编写符合pep8的算法,并在找不到组合时返回[]
,而不是无
。
def get_min_coin_configuration(total_sum, coins, cache=None): # shadowing python built-ins is frowned upon.
# assert(all(c > 0 for c in coins)) Assuming all coins are > 0
if cache is None: # initialize cache.
cache = {}
if total_sum in cache: # check cache, for previously discovered solution.
return cache[total_sum]
elif total_sum in coins: # check if total_sum is one of the coins.
cache[total_sum] = [total_sum]
return [total_sum]
elif min(coins) > total_sum: # check feasibility, if min(coins) > total_sum
cache[total_sum] = [] # no combination of coins will yield solution as per our assumption (all +).
return []
else:
min_configuration = [] # default solution if none found.
for coin in coins: # iterate over all coins, check which one will yield the smallest combination.
results = get_min_coin_configuration(total_sum - coin, coins, cache=cache) # recursively search.
if results and (not min_configuration or (1 + len(results)) < len(min_configuration)): # check if better.
min_configuration = [coin] + results
cache[total_sum] = min_configuration # save this solution, for future calculations.
return cache[total_sum]
assert all([ get_min_coin_configuration(**test[0]) == test[1] for test in
[({'total_sum':25, 'coins':[1, 5, 10]}, [5, 10, 10]),
({'total_sum':153, 'coins':[1, 5, 10, 50]}, [1, 1, 1, 50, 50, 50]),
({'total_sum':100, 'coins':[1, 5, 10, 25]}, [25, 25, 25, 25]),
({'total_sum':123, 'coins':[5, 10, 25]}, []),
({'total_sum':100, 'coins':[1,5,25,100]}, [100])] ])
给定一个值N,如果我们想改变为N美分,并且我们有无限量的S={S1,S2,...,Sm}值的硬币,我们有多少种方法可以改变?硬币的顺序并不重要。不过还有一个额外的限制:你只能用正好是K的硬币换零钱。 例如,对于N=4,k=2和S={1,2,3},有两个解:{2,2},{1,3}。所以输出应该是2。 解决方案: 以上是递归解决方案。但是,我需要有关动态规划解决方案的帮助: 让表示与元素和硬币的总和。
我试图用递归来解决硬币兑换问题,遇到了下面的代码。 问题:给定一些面额的无限硬币,计算它们形成给定数量的方式。 输入: 代码: 我理解代码本身,也理解基本情况,但是我不理解它是如何封装递归/解决方案的。 例如,如果我正在求解,我可以说,因此我可以清楚地“看到”递归。在换硬币的例子中,我无法推断出类似的关系。有人能帮我吗?
给定一个硬币面额列表和一个目标值,我正在尝试创建一个递归函数,它将告诉我生成该值所需的最小硬币数量,然后显示我需要哪些硬币。例如,输入硬币[1,5,10,25],目标为6,输出应该是“你需要2枚硬币:[1,5]”。我写了一个函数,告诉我需要多少硬币,但我也想看看硬币的组合是什么。 这是我刚刚制作的另一个版本-我注意到我的初始解决方案不能很好地处理不可能的输入(例如,只使用五分镍币和一角镍币赚6美分
具体而言,问题是: 给定面额数组<代码>硬币[],每个硬币的限制数组<代码>限制[]和数量<代码>金额,返回所需的最小硬币数量,以获取<代码>金额,或者如果不可能,返回空值。另外,用溶液中使用的每个硬币的数量填充数组 这是我的解决方案: 但它一般不起作用。 我的问题是,例如,在这种情况下: 最佳解决方案是: 并且我的算法给出作为结果。换句话说,它失败了,每当在某种情况下,我将不得不使用比可能的更少
我已经编写了一个代码,用来计算使用递归从1到100之间的任何值可以得到的更改可能性的数量。我不确定项目中的2个方法做了什么(代码中的粗体部分),所以有人能给我解释一下吗?我对Java还很陌生。 我包含了上下文的整个代码,但不确定是否有必要。
下面是最小硬币变化问题的蛮力解决方案。它需要一个int更改,也就是需要进行的更改,以及一系列硬币面值。它返回进行更改所需的最低硬币。 我如何修改它以同时返回一组硬币? 例如,如果要求给出值为[1,2,5]的10美分的零钱,它应该返回2个硬币分钟和一个数组[0,0,2]的2个硬币。