c++ - 用给定面值的最少硬币数量来定额。贪婪的问题

标签 c++ algorithm greedy coin-change

我有C++函数要做。它可以正常工作,但在某些情况下效果不佳-“贪婪问题”。

我的C++代码:

#include <vector>
#include <algorithm>

std::vector<int> ans;

std::vector<int> get_change(const std::vector<int> &denominations, int amount) {
    //pure algo
    std::vector<int> money = denominations;
    std::vector<int> count;
    ans.clear();
    count.assign(money.size(), 0);
    std::sort(money.begin(), money.end());
    int summ = amount;
    for (int i = count.size()-1; i >= 0; i--) {
        count[i] = summ / money[i];
        summ = summ % money[i];
        if (summ==0)
            break;
    }


    //ans generation
    for (int i = 0; i < money.size(); i++)
        for (int j = 0; j < count[i]; j++)
            ans.push_back(money[i]);
    return ans;
}

贪婪问题样本:get_change({ 1, 6, 9 }, 30)将返回{ 1, 1, 1, 9, 9, 9 },但不返回{ 6, 6, 9, 9 }

任务是改进此算法以获得相同的答案。

最佳答案

一种可能的方法是回溯。

回溯是一种通用算法,用于查找某些计算问题(尤其是约束满足问题)的所有(或某些)解决方案,该算法逐步为解决方案构建候选,并在确定候选对象无法解决问题时立即放弃候选(“回溯”)完成有效的解决方案。 (维基百科)

在这里,我们尝试确定每种硬币的硬币数量。

一旦硬币总数高于当前最佳解决方案,就会放弃候选人。而且,这里,在给定的情况下(在i步骤),我们直接计算coins[i]的最大硬币数量,以使总和不高于该数量。

这是一个可能的实现:

#include    <iostream>
#include    <vector>
#include    <algorithm>

std::vector<int> get_change(const std::vector<int>& denominations, int amount) {
    std::vector<int> coins = denominations;
    std::vector<int> n_coins(coins.size(), 0);
    std::vector<int> n_coins_opt(coins.size(), 0);
    int n = coins.size();

    std::sort(coins.begin(), coins.end(), std::greater<int>());

    int sum = 0;    // current sum
    int i = 0;      // index of the coin being examined
    int n_min_coins = amount / coins[n - 1] + 1;
    int n_total_coins = 0;
    bool up_down = true;

    while (true) {          // UP
        if (up_down) {
            n_coins[i] = (amount - sum) / coins[i];     // max number of coins[i]
            sum += n_coins[i] * coins[i];
            n_total_coins += n_coins[i];
            if (sum == amount) {
                if (n_total_coins < n_min_coins) {
                    n_min_coins = n_total_coins;
                    n_coins_opt = n_coins;
                }
                up_down = false;
                sum -= n_coins[i] * coins[i];
                n_total_coins -= n_coins[i];
                n_coins[i] = 0;
                i--;
            }
            else {
                if (i == (n - 1) || (n_total_coins >= n_min_coins)) {   // premature abandon
                    sum -= n_coins[i] * coins[i];
                    n_total_coins -= n_coins[i];
                    n_coins[i] = 0;
                    up_down = false;
                    i--;
                }
                else {
                    i++;
                }
            }

        }
        else {            // DOWN
            if (i < 0) break;
            if (n_coins[i] == 0) {
                if (i == 0) break;
                i--;
            }
            else {
                sum -= coins[i];
                n_coins[i] --;
                n_total_coins--;
                i++;
                up_down = true;
            }
        }
    }

    std::vector<int> ans;

    for (int i = 0; i < coins.size(); i++)
        for (int j = 0; j < n_coins_opt[i]; j++)
            ans.push_back(coins[i]);

    return ans;
}

int main() {
    std::vector<int> coins = { 1, 6, 9 };
    int amount = 30;
    auto n_coins = get_change(coins, amount);

    for (int i = 0; i < n_coins.size(); i++)
            std::cout << n_coins[i] << " ";

    std::cout << "\n";
    return 1;
}

关于c++ - 用给定面值的最少硬币数量来定额。贪婪的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59106330/

相关文章:

c++ - 计算两个数的超表中的第 N 个数

algorithm - 您如何确定问题显示为 "Greedy choice property"?

java - 一种为任务分配时间使总时间最大化的贪心算法

c++ - 在 32、64 位上正确存储容器大小

C++ 库包括矩阵的伪逆?

c++ - eclipse : How to hide a file from Project Explorer?

algorithm - 高效排序算法的实际重要性

algorithm - 如何暴力破解算术难题?

algorithm - 贪心技术与穷举搜索有何不同?

c++ - 关于创建 DBMS 的建议