零用钱

【题目描述】
作為创造產奶纪录的回报,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
【分析】
从样例就可以发现,我们完全可以先把v中大于等于C的先全部支付。这显然是正确的,因为没有必要在已经满足条件时还多给Bessie一些零钱,除非是Bessie自己在写这题。
然后对于每一个星期,尽量取大的面额使得总钱数不超过C,取完后如果没有达到C就找小的面额来补。通俗的说,大的面额是主力,小的面额是救火队员,哪里缺了就补上。用程序语言就是说,当前在使用面值为v[i]的钱,已经支付了j元,而且j+v[i]或v[i-1]>j+v[1]>=C,此处默认v数组已经按照从小到大的顺序排好了。

var
  a,b:array[0..21] of longint;
  i,n,c,sum,t:longint;
  change:boolean;
procedure qsort(l,r:longint);
var
  i,j,temp,mid:longint;
begin
  i:=l; j:=r;
  mid:=a[(l+r) div 2];
  repeat
    while a[i]<mid do inc(i);
    while a[j]>mid do dec(j);
    if i<=j then
    begin
      temp:=a[i];a[i]:=a[j];a[j]:=temp;
      temp:=b[i];b[i]:=b[j];b[j]:=temp;
      inc(i);dec(j);
    end;
  until i>j;
  if l<j then qsort(l,j);
  if i<r then qsort(i,r);
end;
begin
  sum:=0;
  readln(n,c);
  for i:=1 to n do readln(a[i],b[i]);
  qsort(1,n);
  change:=true;
  while change do begin
    change:=false;
    t:=c;
    for i:=n downto 1 do//先取大的面额
      while (b[i]>0)and(t-a[i]>=0) do begin
        dec(b[i]);
        t:=t-a[i];
      end;
    for i:=1 to n do//救火队员出场
      if (b[i]>0)and(t>0) then begin
        dec(b[i]);
        t:=t-a[i];
      end;
    if t<=0 then begin//这个星期支付完毕
      change:=true;
      inc(sum);
    end;
  end;
  write(sum);
end.

转载于:https://www.cnblogs.com/JRX2015U43/p/6533504.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值