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

我有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,9,9 },但不会返回{ 6,9 }

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

zy19890512 回答:用给定面值的最少数量的硬币来定额。贪婪的问题

一种可能的方法是回溯。

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

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

一旦硬币总数高于当前最佳解决方案,就会放弃候选人。而且,这里,在给定情况下(在步骤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;
}
,

这是一个dynamic programming问题。

import java.util.*;
import java.lang.*;
import java.io.*;

class Solution{
    public static void main (String[] args) throws java.lang.Exception{
            System.out.println(getChange(new int[]{1,9},30));
            System.out.println(getChange(new int[]{1},3));
            System.out.println(getChange(new int[]{4,20,500},450));
    }

    private static List<Integer> getChange(int[] denominations,int amount){
            Arrays.sort(denominations);
            List<Integer> ans = new ArrayList<>();
            if(amount <= 0 || denominations[0] > amount) return ans;
            int[][] dp = new int[amount + 1][2];

            for(int i=0;i<denominations.length;++i){
                if(denominations[i] > amount) break;
                dp[denominations[i]][0] = 1;
                dp[denominations[i]][1] = 0;
                for(int j=denominations[i] + 1;j<=amount;++j){
                    if(dp[j-denominations[i]][0] > 0 && (dp[j][0] == 0 || dp[j-denominations[i]][0] + 1 < dp[j][0])){
                       dp[j][0] = dp[j-denominations[i]][0] + 1;
                       dp[j][1] = j-denominations[i];
                    }
                }
            }

            if(dp[amount][0] > 0){
                while(dp[amount][0] != 0){
                    ans.add(amount - dp[amount][1]);
                    amount = dp[amount][1];
                }
            }



            return ans;
    }
}

演示: https://ideone.com/2fYg4F

算法:

  • 这类似于coin change问题。

  • 我们首先对数组中的数字进行排序以进行统一计算。

  • 现在,我们迭代所有数组元素,并使每个数组元素遍历从该元素到最终数量的所有可能量。
  • 现在,仅当我们已完成总金额j时,我们才可以进行金额j - denominations[i](这是一笔总和)。
  • 在这样做的同时,我们还会检查所需的最小硬币数量。如果当前金额为j的金额denominations[i]所需的硬币数量少于dp[j][0]中存储的当前值,那么我们将相应地更新dp[j]中的答案。

  • 最后,我们只是遍历所需的确切硬币并返回答案。

什么是dp [] []

  • 这只是一个简单的2D数组,其中第0 列跟踪最小硬币数量 它的第一个索引中需要的,而2 nd 索引具有先前的硬币索引,因此它具有 最低价值。

  • dp [] []中的2 nd 索引将简化计算以找到确切的硬币值,因为我们只需做amount - dp[amount][1]就可以得到硬币值。

最后,我们只检查dp[amount][0]的值。如果其值为0,则没有解决方案,否则我们将对其进行计算。

,

我将vivek_23的动态解决方案改编为必需的C++语言。

std::vector<int> get_change2(const std::vector<int>& coins,int amount) {
    std::vector<int> denominations = coins;
    std::sort(denominations.begin(),denominations.end());
    std::vector<int> ans;

    if (amount <= 0 || denominations[0] > amount)
        return ans;

    int** dp = new int* [amount + 1];
    for (int i = 0; i < amount + 1; i++) {
        dp[i] = new int[2];
        dp[i][0] = 0;
        dp[i][1] = 0;
    }

    for (int i = 0; i < denominations.size(); i++) {
        if (denominations[i] > amount) break;
        dp[denominations[i]][0] = 1;
        dp[denominations[i]][1] = 0;
        for (int j = denominations[i] + 1; j <= amount; ++j) {
            if (dp[j - denominations[i]][0] > 0 && (dp[j][0] == 0 || dp[j - denominations[i]][0] + 1 < dp[j][0])) {
                dp[j][0] = dp[j - denominations[i]][0] + 1;
                dp[j][1] = j - denominations[i];
            }
        }
    }

    if (dp[amount][0] > 0) {
        while (dp[amount][0] != 0) {
            ans.push_back(amount - dp[amount][1]);
            amount = dp[amount][1];
        }
    }



    return ans;
}
本文链接:https://www.f2er.com/3006917.html

大家都在问