找到产生给定值的最小硬币集
Posted
技术标签:
【中文标题】找到产生给定值的最小硬币集【英文标题】:Finding the minimum set of coins that make a given value 【发布时间】:2021-12-25 07:10:32 【问题描述】:我一直在试图弄清楚是否有办法获得用于找零的最佳最小硬币集。
贪心算法有一个问题,例如如果我们有一组硬币 1, 5, 6, 9,我们想要得到值 11。贪心算法会给我们 9,1, 1 但最佳解决方案是 5, 6
通过阅读site,我发现这种方法可以为我们提供所需的最少硬币总数。有没有办法从中得到一套硬币?
【问题讨论】:
更新动态规划时,只需保留一些数组last_coin[]
,其中last_coin[i]
等于最后添加的任何一个硬币,以便获得最佳硬币子集的总和到i
。然后,可以通过从i
开始并追溯至i - last_coin[i]
直到达到 0 来找到总和为一个数字的实际硬币集合。
@Telescope 如果您不介意可以通过代码向我展示我们将如何做到这一点吗?
【参考方案1】:
我假设您已经知道动态编程方法可以只找到所需的最小数量硬币。假设您想找到创造总价值K
的最小硬币数量。然后,您的代码可能是
vector <int> min_coins(K + 1);
min_coins[0] = 0; // base case
for(int k = 1; k <= K; ++k)
min_coins[k] = INF;
for(int c : coins) // coins[] contains all values of coins
if(k - c >= 0)
min_coins[k] = min(min_coins[k], min_coins[k - c] + 1);
回答您的问题:为了找到实际集合中最小的硬币,我们可以简单地保留另一个数组last_coin[]
,其中last_coin[k]
等于之前的硬币最后添加到最佳硬币集合中,总和为k
。为了说明这一点:
vector <int> min_coins(K + 1), last_coin(K + 1);
min_coins[0] = 0; // base case
for(int k = 1; k <= K; ++k)
min_coins[k] = INF;
for(int c : coins)
if(k - c >= 0)
if(min_coins[k - c] + 1 < min_coins[k])
min_coins[k] = min_coins[k - c] + 1;
last_coin[k] = c; // !!!
这如何让你找到这组硬币?假设我们想找到总和为K
的最佳硬币集。然后,我们知道last_coin[K]
持有集合中的一个硬币,因此我们可以将last_coin[K]
添加到集合中。之后,我们从K
中减去last_coin[K]
并重复直到K = 0
。显然,这将构建一个(不一定)最小大小的硬币集合,总和为 K。
可能的实现:
int value_left = K;
while(value_left > 0)
last_coin[value_left] is added to the set
value_left -= last_coin[value_left]
【讨论】:
以上是关于找到产生给定值的最小硬币集的主要内容,如果未能解决你的问题,请参考以下文章