bluecode-最优硬币组合问题

26 阅读1分钟

问题描述

小C有多种不同面值的硬币,每种硬币的数量是无限的。他希望知道,如何使用最少数量的硬币,凑出给定的总金额N。小C对硬币的组合方式很感兴趣,但他更希望在满足总金额的同时,使用的硬币数量尽可能少。

例如:小C有三种硬币,面值分别为 125。他需要凑出总金额为 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;
}