USACO 邮票 Stamps
f[x]表示组成 x 最少需要的邮票数量
一一举例
最多贴5张邮票,有三种邮票可用,分别是1分,3分,8分
组成0分需要0张邮票 ——f[0]=0
组成1分需要在0分的基础上加上一张1分邮票 ——f[1]= f[0]+1 =1 (单位:张)
组成2分需要在1分的基础上加上一张1分邮票 ——f[2]= f[1]+1 =2
组成3分需要 min{在2分的基础上加上一张1分邮票,在0分的基础上加上一张3分邮票} ——f[3]=min{ f[2]+1 , f[0]+1 } = min{ 3 , 1} = 1
组成4分需要在3分的基础上加上一张1分邮票 ——f[4]= f[3]+1 =2
…… 组成7分需要在6分的基础上加上一张1分邮票 ——f[7]= f[6]+1 =3
组成8分需要 min{在7分的基础上加上一张1分邮票,在0分的基础上加上一张8分邮票} ——f[8]=min{ f[7]+1 , f[8 - 8]+1 }=1
……
继续推下去的话就会发现规律
当 x 到达一定邮票面值时就会化简
状态转移方程则为
f[i] = min{ f[i-1]+1 , f[i-a[j]]+1 }
代码参考:
1 type 2 tlist=array[0..2000000] of longint; 3 var 4 n,k,i,j:longint; 5 a,f:array[0..2000000] of longint; 6 function min(a,b:longint):longint; 7 begin 8 if a<b then exit(a); 9 exit(b); 10 end; 11 procedure qsort(var a : tlist); 12 procedure sort(l,r: longint); 13 var 14 i,j,x,y: longint; 15 begin 16 i:=l; 17 j:=r; 18 x:=a[(l+r) div 2]; 19 repeat 20 while a[i]<x do 21 inc(i); 22 while x<a[j] do 23 dec(j); 24 if not(i>j) then 25 begin 26 y:=a[i]; 27 a[i]:=a[j]; 28 a[j]:=y; 29 inc(i); 30 dec(j); 31 end; 32 until i>j; 33 if l<j then 34 sort(l,j); 35 if i<r then 36 sort(i,r); 37 end; 38 begin 39 sort(1,k); 40 end; 41 begin 42 assign(input,'stamps.in'); 43 assign(output,'stamps.out'); 44 reset(input); 45 rewrite(output); 46 readln(n,k); 47 for i:=1 to k do 48 read(a[i]); 49 qsort(a); //快排 50 f[0]:=0; 51 for i:=1 to 2000000 do //可用邮票总数 * 邮票最大面值 52 begin //温馨提示pascal别用while循环 53 f[i]:=maxlongint; 54 for j:=1 to k do 55 if i>=a[j] then 56 if f[i]>f[i-a[j]]+1 then f[i]:=f[i-a[j]]+1; 57 if f[i]>n then break; //当使用的邮票数量大于n时退出循环 58 end; 59 writeln(i-1); //退出时f[i]大于n,故 -1 60 close(input); 61 close(output); 62 end.