团体程序设计天梯赛 L3-001 凑零钱 (30分)(0/1背包)
题目链接:
L3-001 凑零钱 (30分)
思路:
将每个硬币的面值既当作它的价值也当作它所消耗的容量,我们的目标即是在容量为m
的情况下,所能得到的最大总价值能否为m
;
既然是求一定容量下的最大价值,那么就是经典的0/1背包问题了;
我们需要打印出最大价值的情况下所选取的所有硬币,我们只能从后往前打印,因此我们将初始的价值降序排序,从而在从后往前选取路径时先选取的是面值小的硬币;
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5;
int n, m, w[maxn], dp[maxn], flag[maxn][maxn];
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#else
ios::sync_with_stdio(false);
cin.tie(0);
#endif
cin >> n >> m;
for(int i = 0; i < n; i++) cin >> w[i];
sort(w, w + n, greater<int>());
for(int i = 0; i < n; i++)
for(int j = m; j >= w[i]; j--)
if(dp[j] <= dp[j - w[i]] + w[i]) {
flag[i][j] = true;
dp[j] = dp[j - w[i]] + w[i];
}
if(dp[m] != m) { cout << "No Solution\n"; exit(0); }
int ans = m, pos = n - 1;
while(ans) {
while(flag[pos][ans] == false) --pos;
cout << w[pos];
ans -= w[pos--];
if(ans) cout << ' ';
}
return 0;
}