零用錢

【題目描述】
做為創造產奶紀錄的回報,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.
相關文章
相關標籤/搜索