题意:
给出n枚钱币,要求买价值为m的物品,要求输出具体所用的钱币,如有多种情况输出字典序最小的情况。
思路:
这题就是01背包的变种,状态转移方程很好写:dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+c[i])
主要难点在于怎么处理多种情况最后输出,基本思路是一开始将钱币按从大到小排序,在状态转移的过程中用hash[i][j]保存是否选取了当前钱币i,这样最后对dp[n][m]倒序输出时会优先输出币值小的从而符合字典序。
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
const int maxn = 10050;
int num[maxn], dp[maxn][150];
int pos[maxn][150];int main() {int n, m;scanf("%d%d", &n, &m);for (int i = 1; i <= n; i++)scanf("%d", &num[i]);sort(num+1, num + n+1, greater<int>());for (int i = 1; i <= n; i++) {for (int j = num[i]; j <= m; j++) {if (dp[i - 1][j] <= dp[i-1][j - num[i]] + num[i]) {dp[i][j] = dp[i-1][j - num[i]] + num[i];pos[i][j] = 1;} else {dp[i][j] = dp[i - 1][j];pos[i][j] = 0;}}} if (dp[n][m] != m)printf("No Solution\n");else {vector<int> res;int road = m,index=n;while (road > 0) {if (pos[index][road]==1) {res.push_back(num[index]);road -= num[index];}index--;}for (int i = 0; i<res.size(); i++) {if (i == 0)printf("%d", res[i]);elseprintf(" %d", res[i]);}} return 0;
}