概述
P1658 购物
提交 2.48k
通过 1.16k
时间限制 1.00s
内存限制 125.00MB
题目描述
你就要去购物了,现在你手上有N种不同面值的硬币,每种硬币有无限多个。为了方便购物,你希望带尽量少的硬币,但要能组合出1到X之间的任意值。
输入格式
第一行两个数X、N,以下N个数,表示每种硬币的面值。
【数据规模】
对于30%的数据,满足N≤3,X≤20;
对于100%的数据,满足N≤10,X≤1000.
输出格式
最少需要携带的硬币个数,如果无解输出-1.
输入输出样例
输入 #1
20 4
1 2 5 10
输出 #1
5
题目链接:https://www.luogu.com.cn/problem/P1658
1.首先我们要判断数组内是否存在1,因为面额1只有1可以组成,而且如果存在面值1的硬币,是一定可以组成出1-x的面值。
2.每次尽量用最大面值硬币组合,这样子才可以组成出最小的携带数。因此用sort排序。
上样例分析:
第一次取1:
reach=1;当前可以组成的面额值
第二次取2:1,2,3
观察:3是利用1+2得出的,如果我们当前可以取到的面额为reach,那么我们再携带的一个硬币a[i],1–reach+a[i]都是可以组合出来的,因为2可以和1–reach的面值任意组合都是可行的所以reach更新为reach+=a[i];reach为3
第三次取2:1,2,3,4,5
与上同理reach为5
#include<iostream>
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define speed(x) ios::sync_with_stdio(false), cin.tie(x), cout.tie(x)
#define bug(x) cout << #x << " == " << x << 'n';
const ll int MAX_N = 5e5 + 5;
using namespace std;
const int Maxn=1005;
int a[MAX_N]={0};
int main()
{
int n,x;
cin>>x>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
if(a[1]!=1)//需要可以组合出1-x的面值,而面值1只有1本身可以组合,
{
cout<<-1<<'n';//而且如果有面值1无论后面的面值是怎么样的,都可以组合出1-x的面值例:1 1 1 1 1 .....
return 0;
}
int reach=0;//可以组成的面额值
int ans=0;
while(reach<x)
{
int i=n;
for(;i>=1;i--)//尽量找最大的
{
if(a[i]<=reach+1)
break;
}//1~reach面额的钱都可以组成,所以只需要找最大面额的钞票,
//该钞票可以和reach+1-a[i]的钱组成reach+1或者直接等于reach+1
reach+=a[i];//a[i]可以和reach+1-a[i]组成reach+1,同理a[i]可以和reach+2-a[i](reach+2-a[i]<=reach即可)组成reach+2....
ans++;//携带的钞票增加1个;
}
printf("%dn",ans);
return 0;
}
最后
以上就是彪壮小蝴蝶为你收集整理的P1658 购物(贪心算法)的全部内容,希望文章能够帮你解决P1658 购物(贪心算法)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复