题目描述
作为创造产奶纪录的回报,Farmer John决定开始每个星期给Bessie一点零花钱。FJ有一些硬币,一共有N(1 < = N < = 20)种不同的面额。每一个面额都能整除所有比它大的面额。他想用给定的硬币的集合,每个星期至少给Bessie某个零花钱的数目C(1 < = C < = 100000000)。请帮他计算他最多能支付多少个星期的零花钱。
输入格式
第一行:两个由空格隔开的整数:N和C。
第2到第N+1行:每一行有两个整数表示一个面额的硬币:硬币面额V(1 < = V < = 100,000,000)和Farmer John拥有的该面额的硬币数B(1 < = B < = 1,000,000)。
输出格式
第一行:一个单独的整数,表示Farmer John最多能给Bessie支付多少个星期至少为C的零用钱。
样例输入
3 6 10 1 1 100 5 120
样例输出
111
开始分析,我们有不同面额的硬币,如果我们手里的一些硬币面额比c大,我们就要“亏本”将此硬币直接给他,对于面额比c小的硬币,我们要利用贪心原则,从面额较大的硬币开始给他。
分段代码如下
我们首先定义一个结构体,用来存储硬币的面额和数量
struct text
{
int a;//面额
int b;//数量
};
然后我们就要创建结构体数组用来储存每一种硬币的信息,对面面额比c大的硬币,不作存储并且直接将数量加到总星期数里
int sum = 0;//总共可以发零花钱的星期数
std::cin>>n>>c;
text t[21];
int lin = 0;
for(int i = 0;i<n;i++){
int l1,l2;
std::cin>>l1>>l2;
if(l1>c){
sum+=l2;
}//若面额比c大,则sum直接加上数量且不计入结构体数组中
else{
t[lin].a = l1;
t[lin].b = l2;
lin++;
}
}
接下来对结构体数组进行升序排列,为后面贪心铺垫
bool cmp(text aa,text bb){
return aa.a<bb.a;
//升序排列
}
sort(t,t+lin,cmp);//注意前两项左闭右开
为了将所有钱都分完,需要写一个while(1)循环,运用贪心算法开始从最大面额开始,令x = c如果t[i].b>0&&x>=t[i].a为真,就要循环将x减去t[i].a直到x<t[i].a
while(1){
int x = c;
for(int i = lin-1;i>=0;i--){//从最大面额开始
if(t[i].b>0&&x>=t[i].a){
while(x>=t[i].a&&t[i].b>0){
x-=t[i].a;
t[i].b--;
}
}
}
sum++;//每经过一次循环代表结了一个星期的钱
}
光是如此是不够的,因为从大往小完成这些步骤后x有可能>0(给他的钱不够,还缺一点),我们就需要增加一个判断,如果x>0我们需要从小往大找到还有数量(t[i]>0)的硬币给他
if(x>0){
for(int i = 0;i<lin;i++){
if(t[i].b>0){
x-=t[i].a;
t[i].b--;
break;
}
}
}
最后判断一下当我们手里已经没有足够的钱可以发时,即x>0,跳出循环
if(x>0)break;
整理代码如下
#include<bits/stdc++.h>
using namespace std;
struct text
{
int a;
int b;
};
bool cmp(text aa,text bb){
return aa.a<bb.a;
}
int main()
{
int n,c;
int sum = 0;
std::cin>>n>>c;
text t[21];
int lin = 0;
for(int i = 0;i<n;i++){
int l1,l2;
std::cin>>l1>>l2;
if(l1>c){
sum+=l2;
}
else{
t[lin].a = l1;
t[lin].b = l2;
lin++;
}
}
sort(t,t+lin,cmp);
while(1){
int x = c;
for(int i = lin-1;i>=0;i--){
if(t[i].b>0&&x>=t[i].a){
while(x>=t[i].a&&t[i].b>0){
x-=t[i].a;
t[i].b--;
}
}
}
if(x>0){
for(int i = 0;i<lin;i++){
if(t[i].b>0){
x-=t[i].a;
t[i].b--;
break;
}
}
}
if(x>0)break;
sum++;
}
std::cout<<sum;
}
运行示例如下