该问题是典型的多重背包问题,不懂的可看该视频 https://www.bilibili.com/video/BV1xv411H7ST/?spm_id_from=333.999.0.0&vd_source=81678c8c7b5ba3c955908e3572e2335d

多重背包一般是求装满容量为j的背包的最大价值是多少,其递推公式为

dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

而本题是求最少零钱个数,所以得变换两处:用min,且将value[i]改为+1(求的是零钱数目,而非价值)

#include<iostream>
using namespace std;
#include<vector>

int T, m;

int main() {
  cin >> T;
  while (T--) {
      vector<int> money{1, 5, 10};
      vector<int> nums(3);

      cin >> m;

      for (int i = 0;i < 3;i++)
          cin >> nums[i];

      vector<int> dp(m + 1, 101);  // 默认初始化得大于100,便于比较
      dp[0] = 0;  // 如果dp[0]也为101 的话,后⾯所有推导出来的值都是101了

      for (int i = 0;i < 3;i++)  // 遍历零钱的面值大小
          for (int k = 0;k < nums[i];k++)  // 遍历各个面值的零钱的数目
              for (int j = m;j >= money[i];j--)
                  dp[j] = min(dp[j], dp[j - money[i]] + 1);

	  // 当出现该情况时,则证明凑不出m
      if (dp[m] == 101)
          cout << -1 << endl;
      else
          cout << dp[m] << endl;  // 当dp[m]非101时,则是最小的零钱数
  }
  return 0;
}