您的位置:首页 > 其它

L3-001. 凑零钱 - 【01背包 + 记录路径 + 裸裸裸题】

2017-10-06 20:30 330 查看

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 9

5 9 8 7 2 3 4 1

输出样例1:

1 3 5

输入样例2:

4 8

7 2 4 3

输出样例2:

No Solution

题意:给你n和m,表示有n种硬币,总价为m元,然后给你n个数,表示有n个单位货币,问你能不能由这n个货币其中的一些恰好组成m元,如果可以的话,从小到大输出;

分析: 乍一看可以dfs,但是看了时限,……… 还是老老实实背包吧,直接一个01背包记录路径即可,就是中间加个排序,因为要求是要从小到大来输出, 这里呢简单解释下 pre[j]=j−v[i],仔细看下就能发现存的恰好是dp数组里的坐标, 就和单链表里的next数组类似,ans数组呢是为了输出时使用的,仔细体会体会。

参考代码

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int pre
,dp
,v
,ans
;

void p(int x){
if(pre[x] == 0){
cout<<ans[x];return;
}
p(pre[x]);
cout<<' '<<ans[x];
}

int main(){
ios_base::sync_with_stdio(0);
int n,m;cin>>n>>m;
for(int i = 0;i < n;i++)cin>>v[i];
for(int i = 0;i < N;i++)pre[i] = -1,dp[i] = -INF;
sort(v,v+n);
dp[0] = 0; //和01背包类似,因为是恰好装满,其他只要赋上负无穷
for(int i = 0;i < n;i++){
for(int j = m;j >= v[i];j--){
if(dp[j] <= dp[j-v[i]]+1){
dp[j] = dp[j-v[i]]+1;
ans[j] = v[i];
pre[j] = j - v[i];
}
}
}
if(dp[m] <= 0) cout<<"No Solution";
else p(m);
cout<<endl;
return 0;
}


如有错误或遗漏,请私聊下UP,ths
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: