【DFS】Poj1010 STAMPS

本文介绍了一个关于邮票组合的编程问题,旨在寻找满足特定条件的最佳邮票组合方案。通过深度优先搜索(DFS)算法实现,重点在于如何避免重复方案并确保找到最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

  用所给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.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值