L3-001. 凑零钱

来源:互联网 发布:软件测试 西安 编辑:程序博客网 时间:2024/05/29 04:45

L3-001. 凑零钱

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有104枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。

输入格式:

输入第一行给出两个正整数:N(<=104)是硬币的总个数,M(<=102)是韩梅梅要付的款额。第二行给出N枚硬币的正整数面值。数字间以空格分隔。

输出格式:

在一行中输出硬币的面值 V1 <= V2 <= ... <= Vk,满足条件 V1 + V2 + ... + Vk = M。数字间以1个空格分隔,行首尾不得有多余空格。若解不唯一,则输出最小序列。若无解,则输出“No Solution”。

注:我们说序列{A[1], A[2], ...}比{B[1], B[2], ...}“小”,是指存在 k >= 1 使得 A[i]=B[i] 对所有 i < k 成立,并且 A[k] < B[k]。

输入样例1:
8 95 9 8 7 2 3 4 1
输出样例1:
1 3 5
输入样例2:
4 87 2 4 3
输出样例2:
No Solution

提交代码

解题思路:如果是单纯的问是否可以满足,那么相信很多人都没有任何问题,因为这就是一道单纯的背包问题,加上要输出那几个金额的货币时,
可能就有点懵了,其实只需要在判断是否放入背包是标记一下就可以,定义一个book数组进行标记,开始时全部初始化为FALSE,比如
book[i][j],背包中金额为j时放入了第i枚硬币,就标记为true,否则就不管它,可以对数据进行一个初始化排序,题目是要求输出数值最小的
那几只,所以可以进行一个从打到小的排序。但后面查找是否放入了背包的时候需要从后面开始查找。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define N 10000+10int book[N][110];int dp[110];int val[N];bool cmp(int a,int b){return a > b;}int main(){//freopen("input.txt","r",stdin);int n,m;scanf("%d%d",&n,&m);for(int i = 0;i < n;i++){scanf("%d",&val[i]);}sort(val,val+n,cmp);memset(book,false,sizeof(book));memset(dp,0,sizeof(dp));//初始化,一个都没有放入 for(int i = 0; i < n; i++) {        for(int j = m; j >= val[i]; j--) {            if(dp[j] <= dp[j-val[i]] + val[i]) {//一定要加上等于,题目是要求 输出面值最小的那几只                 book[i][j] = true;//表示背包里面数值等于j是硬币i已放入                 dp[j] = dp[j-val[i]] + val[i];            }        }    }vector<int>v;if(dp[m] != m){printf("No Solution\n");}else{int i = n-1; //这里是从最后一个节点开始遍历,千万从第一个位置开始遍历,数据时从大到小排的序 while(m > 0){if(book[i][m]){v.push_back(val[i]);m -= val[i];}i--;}for(i = 0;i < v.size();i++){if(i == 0){printf("%d",v[i]);}else{printf(" %d",v[i]);}}printf("\n");}return 0;} 



原创粉丝点击