我有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 }
。
任务是改进此算法以获得相同的答案。
答案 0 :(得分:2)
一种可能的方法是回溯。
回溯是一种通用算法,用于查找某些计算问题(尤其是约束满足问题)的所有(或某些)解决方案,该算法逐步为该解决方案构建候选对象,并在确定该候选对象后立即放弃候选对象(“回溯”)。候选人可能无法完成有效的解决方案。 (维基百科)
在这里,我们尝试确定每种硬币的硬币数量。
一旦硬币总数高于当前最佳解决方案,就会放弃候选人。而且,这里,在给定情况下(在步骤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;
}
答案 1 :(得分: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,6,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;
}
}
算法:
这类似于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
,则没有解决方案,否则我们将对其进行计算。
答案 2 :(得分: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;
}