邮票问题(转)

邮票问题(Stamps)
问题描述:
给定一个信封,最多只允许粘贴N(N£100)张邮票,我们现在有m(m £100)种邮票,面值分别为:x1,x2,……,xm分,(xi£255,为正整数),并假设各种邮票都有足够多张。要求计算所能获得的邮资最大范围。即求最大值MAX,使在1—MAX之间的每一个邮资值都能得到。
例如,N=4,有2种邮票,面值分别为1分、4分,于是可以得到1—10分和12分、13分、16分邮资,由于得不到11分和15分,所以邮资的最大范围MAX=10。

输入格式:
从键盘输入一个文本文件的文件名。该文件第1行为最多粘贴的邮票张数N;第2行为邮票种数m;以下m行各有一个数字,表示邮票的面值xi。

输出格式:
1. 若最大范围为空,则在屏幕上输出MAX=0
2. 若最大范围不为空,则把结果输出到屏幕上:
MAX=xxx xxx表示邮资最大范围

算法分析:
本题可以看成是一个集合问题,即求在贴的邮票不多于n张的可达邮资集。集合问题的关键在于判定元素是否在集合中,对本题而言,是判断某个邮资是否在贴不多于n张邮票可达。这个判断问题可以用递归的方法来解决。设当前考虑的邮资值为max,最多允许贴n张邮票,记为(max,n)。如果首先贴一张面值为xi的邮票,那么剩下的问题是(max-xi,n-1)的问题。如果(max-xi,n-1)可解,那么(max,n)问题也可解。
进一步,这个递归的算法可以转化为递推的算法来解决。设pieces[value]表示邮资为value时所需最少的邮票数,pieces[value]=min{pieces[value-xi]+1}。当pieces[value]£n时,问题(max,n)可解,否则无解。
递推算法可以描述为:
for i:=1 to m do if value-x[i]>=0 then
begin 
if pieces[value]=0 then pieces[value]:=pieces[value-x[i]]+1;
if pieces[value]>pieces[value-x[i]]+1 then pieces[value]:=pieces[value-x[i]]+1;
end;
例如:最多可贴4张邮票,邮票有两种,面值分别为1和4。按照上述算法可得下表:
value pieces[value]
0 0
1 min{pieces[1-1]+1}=1
2 min{pieces[2-1]+1}=2
3 min{pieces[3-1]+1}=3
4 min{pieces[4-1]+1,pieces[4-4]+1}=1
5 min{pieces[5-1]+1,pieces[5-4]+1}=2
6 min{pieces[6-1]+1,pieces[6-4]+1}=3
7 min{pieces[7-1]+1,pieces[7-4]+1}=4
8 min{pieces[8-1]+1,pieces[8-4]+1}=2
9 min{pieces[9-1]+1,pieces[9-4]+1}=3
10 min{pieces[10-1]+1,pieces[10-4]+1}=4
11 min{pieces[11-1]+1,pieces[11-4]+1}=5(>4)

程序分析:
{$R-,V-,S-}
program gdkoi98_7_ Stamps;
uses crt;
var x:array [1..255] of byte; {各种邮票的面值}
pieces:array [0..30000] of byte;{pieces[value]表示邮资为value时最少需要的邮票数}
max,m,n,i,j:integer;
filename:string;
f:text;

begin
{读入数据}
write('Input File:');
readln(filename);
assign(f,filename);
reset(f);
readln(f,n);
readln(f,m);
for i:=1 to m do readln(f,x[i]);
close(f);

fillchar(pieces,sizeof(pieces),0);
max:=0;
repeat
max:=max+1;
{计算邮资为max最少需要的邮票张数}
for i:=1 to m do if max-x[i]>=0 then
begin
if pieces[max]=0 then pieces[max]:=pieces[max-x[i]]+1;
if pieces[max]>pieces[max-x[i]]+1 then pieces[max]:=pieces[max-x[i]]+1;
end;
{判断所需最少邮票张数是否超过n张}
if (pieces[max]=0) or (pieces[max]>n) then
begin
writeln('MAX=',max-1);
exit;
end;
until false;
end.

posted @ 2011-08-24 17:59  恰个烂苹果  阅读(846)  评论(0编辑  收藏  举报