【问题标题】: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 如果您不介意可以通过代码向我展示我们将如何做到这一点吗?

标签: math dynamic-programming greedy


【解决方案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]
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-15
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-27
    • 1970-01-01
    相关资源
    最近更新 更多