问题描述
小C有多种不同面值的硬币,每种硬币的数量是无限的。他希望知道,如何使用最少数量的硬币,凑出给定的总金额N。小C对硬币的组合方式很感兴趣,但他更希望在满足总金额的同时,使用的硬币数量尽可能少。
例如:小C有三种硬币,面值分别为 1, 2, 5。他需要凑出总金额为 18。一种最优的方案是使用三个 5 面值的硬币,一个 2 面值的硬币和一个 1 面值的硬币,总共五个硬币。
测试样例
样例1:
输入:
coins = [1, 2, 5], amount = 18
输出:[5, 5, 5, 2, 1]
样例2:
输入:
coins = [1, 3, 4], amount = 6
输出:[3, 3]
样例3:
输入:
coins = [5], amount = 10
输出:[5, 5]
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
vector<int> solution(vector<int> coins, int amount) {
// 初始化dp数组,dp[i]表示金额i所需的最少硬币数
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0; // 金额0不需要任何硬币
// 填充dp数组
for (int i = 1; i <= amount; ++i) {
for (int coin : coins) {
if (coin <= i && dp[i - coin] != INT_MAX) {
dp[i] = min(dp[i], dp[i - coin] + 1);
}
}
}
// 如果无法凑出金额,返回空列表
if (dp[amount] == INT_MAX) {
return {};
}
// 回溯找出硬币组合
vector<int> result;
int remaining = amount;
// 为了优先使用大面值硬币,将硬币面值降序排序
sort(coins.begin(), coins.end(), greater<int>());
while (remaining > 0) {
for (int coin : coins) {
if (coin <= remaining && dp[remaining - coin] == dp[remaining] - 1) {
result.push_back(coin);
remaining -= coin;
break;
}
}
}
return result;
}
int main() {
// Add your test cases here
vector<int> result = solution({1, 2, 5}, 18);
for (int num : result) {
cout << num << " ";
}
cout << endl;
cout << (result == vector<int>({5, 5, 5, 2, 1})) << endl;
return 0;
}