题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805402305150976
题意:
n个硬币,每一个有一个特有的价值,一个硬币只有一个,要求选取一些硬币使得他们的价值刚好是m
输出字典序最小的方案。
思路:
最近好久没有刷题了连PAT都好久没动了这样不行啊。连背包都有点不大会了。赶紧把PAT30分的刷完去刷洛谷了。
硬币是一个weight和value相同的物品,背包的容量就是m
问题转换成尽量让包中的价值大,背包中的最大价值都无法到达m说明没有答案。
价值是不可能超过m的,因为weight和value相同,weight限制了。
用一个bool二维数组来保存某一个方案中有没有这个硬币。
因为要求输出字典序最小的方案,所以刚开始先从大到小来排序,先考察大的,当小的和当前价值一样的时候也进行更新。
这时候的更新就是将更小的一个方案进行更新。
在逆序跑bool数组存方案就行了。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<map> 4 #include<set> 5 #include<iostream> 6 #include<cstring> 7 #include<algorithm> 8 #include<vector> 9 #include<cmath> 10 #include<stack> 11 #include<queue> 12 13 #define inf 0x7fffffff 14 using namespace std; 15 typedef long long LL; 16 typedef pair<string, string> pr; 17 18 int n, m; 19 const int maxn = 1e4 + 5; 20 int val[maxn]; 21 bool choice[maxn][105]; 22 int dp[maxn]; 23 24 bool cmp(int a, int b){ 25 return a > b; 26 } 27 28 int main() 29 { 30 scanf("%d%d", &n, &m); 31 for(int i = 0; i < n; i++){ 32 scanf("%d", &val[i]); 33 } 34 sort(val, val + n, cmp); 35 for(int i = 0; i < n; i++){ 36 for(int j = m; j >= val[i]; j--){ 37 if(dp[j] <= dp[j - val[i]] + val[i]){ 38 choice[i][j] = true; 39 dp[j] = dp[j - val[i]] + val[i]; 40 } 41 } 42 } 43 if(dp[m] != m)printf("No Solution "); 44 else{ 45 vector<int>ans; 46 int now = m, id = n - 1; 47 while(now > 0){ 48 if(choice[id][now]){ 49 ans.push_back(val[id]); 50 now -= val[id]; 51 } 52 id--; 53 } 54 printf("%d", ans[0]); 55 for(int i = 1; i < ans.size(); i++){ 56 printf(" %d", ans[i]); 57 } 58 printf(" "); 59 } 60 return 0; 61 }