零用钱

【题目描述】
做為创造產奶纪录的回报,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.
相关文章
相关标签/搜索