题意:
给出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]); else printf(" %d", res[i]); } } return 0; }