2.零花钱(贪心)

题目描述

作为创造产奶纪录的回报,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;
}

运行示例如下 

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值