题目大意:
用所给m种邮票凑成总面值为n的邮票组,找出一个方案要求满足邮票张数不大于4,邮票种类数尽可能多,在此基础上要求邮票张数最小,再在此基础上选最大面额最大的邮票组。若有多种方案满足以上几点输出'tie',若不存在方案输出'none'。
方法:dfs
思路:
暴搜即可,对剪枝要求不高(或者说没要求),每次在m种邮票中选一种,选1~4次即可,主要是判断符合题意的方案有点麻烦,但总体很简单,可以锻炼编码能力,另外要注意的是有的方案之间只是顺序颠倒了,但实际上是一样的,算作一种,为了避免重复而影响结果,在每次选择邮票时邮票编号必须不小于之前的,可以等于因为每种邮数量是无限的,这样问题就解决了。
代码(63ms)
program stamp;
var
ans,w:array[0..4]of longint;
a,f:array[0..100]of longint;
b:array[0..100]of boolean;
n,i,m,j,s,maxt,minx,maxy,x:longint;
function max(x,y:longint):longint;
begin
if x>y then max:=x else max:=y;
end;
procedure dfs(x,y,t,l,u:longint);//x表示当前是第几次选择,y表示最大面额,t表示邮票种类数,l表示客户编号,u表示前一次选择的邮票编号
var i,c:longint;
begin
if s=f[l] then
begin
if t>maxt then begin ans:=w; maxt:=t; minx:=x;maxy:=y; end
else if (t=maxt)and(x<minx) then begin ans:=w; maxt:=t; minx:=x; maxy:=y;end
else if (t=maxt)and(x=minx)and(y>maxy) then begin ans:=w; maxt:=t; minx:=x; maxy:=y; end
else if (t=maxt)and(x=minx)and(y=maxy) then ans[0]:=ans[0]+1;//统计方案
end
else if (s<f[l])and(x<=4) then
for i:=u to m do
begin
s:=s+a[i];c:=ord(b[i]=false); b[i]:=true; w[x]:=a[i];
if s<=f[l] then dfs(x+1,max(y,a[i]),t+c,l,i);
s:=s-a[i]; if c=1 then b[i]:=false;
end;
end;
begin
while not eof do//多组数据
begin
read(x); i:=0;
while x<>0 do
begin i:=i+1; a[i]:=x; read(x); end; m:=i;
read(x); i:=0;
while x<>0 do
begin i:=i+1; f[i]:=x; read(x); end; n:=i;
for i:=1 to n do
begin s:=0; maxt:=0; maxy:=0; minx:=4; fillchar(b,sizeof(b),false); fillchar(ans,sizeof(ans),0);dfs(1,0,0,i,1);
if maxt=0 then writeln(f[i],' ---- none') else begin
write(f[i],' (',maxt,'): ');
if ans[0]=0 then begin
for j:=1 to minx-1 do//注意要减1,因为minx记录的是当前是第几次选择
write(ans[j],' ');writeln; end else writeln('tie'); end;//输出要注意
end;
end;
end.