题目链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805402305150976
题目大意:
给出n枚货币的面值,给定某一待付款项,要求你给出一个“最小的”货币序列付款。这里“最小的”概念可以理解成字典序的概念。
0-1背包问题,表示在1到i之间,是否有序列和满足为j。初始化。且有
。而select[i][j]表示第i个元素是否在序列和满足为j的序列中。
参考代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
const int M = 105;
int main() {
int n, m;
cin >> n >> m;
vector<int> v(n + 1);
int dp[M][M],select[N][M]; //改成bool型测试点3不通过。
for (int i = 1; i <= n; ++i)
cin >> v[i];
sort(v.begin() + 1, v.end(), greater<int>());
dp[0][j] = select[0][j] = true;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
dp[i][j] = dp[i - 1][j]; //dp[i][j]表示才从1到i元素中,能否找出和为j的序列。
if (j >= v[i]) {
dp[i][j] = dp[i-1][j] || dp[i - 1][j - v[i]];
if (dp[i - 1][j - v[i]])
select[i][j] = true;
}
}
}
if (!dp[n][m]) {
cout << "No Solution";
} else {
for (int i = n; i >= 1; --i)
if (select[i][m]) {
cout << v[i];
m -= v[i];
if(m) cout << " "; //m表示当前序列和。
}
}
return 0;
}