[USACO 1.4.1] Packing Rectangles

[题目描述]

Packing Rectangles

铺放矩形块

IOI 95


给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠。所谓最小矩形指该矩形面积最小。
所有4个矩形块的边都与封闭矩形的边相平行,图1示出了铺放4个矩形块的6种方案。这6种方案仅只是可能的基本铺放方案。因为其它方案能由基本方案通过旋转和镜像反射得到。
可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长。

PROGRAM NAME: packrec

INPUT FORMAT

共有4行。每一行用两个正整数来表示一个给定的矩形块的两个边长。矩形块的每条边的边长范围最小是1,最大是50

SAMPLE INPUT (file packrec.in)

1 2
2 3
3 4
4 5

OUTPUT FORMAT

总行数为解的总数加1。第一行是一个整数,代表封闭矩形的最小面积(子任务A)。接下来的每一行都表示一个解,由数P和数Q来表示,并且P≤Q(子任务B)。这些行必须根据P的大小按升序排列,P小的行在前,大的在后。且所有行都应是不同的。

SAMPLE OUTPUT (file packrec.out)

40
4 10
5 8


[解题思路]

IOI 的神级题啊、 Orz...

看数据范围应该是搜,但具体方法想了好久都没有思路。枚举长宽吧,检验复杂度过高,并且不好实现,要用栈记录可以放的点;迭代枚举最小面积吧,同样还是要枚举长宽......

绝望之中百度了下,发现神犇的Bo,观摩入口在这里

其实就是题目中给定的几种基本情况(看题的时候根本没注意... = =、),枚举4个矩形的排列顺序,再枚举每一种摆放方法,记录最优解,排序输出即可。

130+行的代码,观Bo之后,自己重新手枚一遍的结果,一伪代码照着敲的...


[Code]

{
ID: zane2951
PROG: packrec
LANG: PASCAL
}

program packrec;
var
   x,y,q,l,h:array[0..5] of longint;
   xx,yy:array[0..1111] of longint;
   f:array[0..201,0..201] of boolean;
   ans,top,i,i1,i2,i3,i4:longint;

//----------max------------
function max(a,b:longint):longint;
begin
   if a>b then exit(a) else exit(b);
end;

//-----------up------------
procedure up(hh,ll:longint);
var
   tmp:longint;

begin
   if ll<hh then begin tmp:=ll; ll:=hh; hh:=tmp; end;
   if hh*ll<=ans then
      if hh*ll<ans then
         begin
            ans:=hh*ll;
            top:=1;
            xx[top]:=hh;
            yy[top]:=ll;
            f[hh,ll]:=true;
            f[ll,hh]:=true;
         end
         else
            if not f[hh,ll] then
               begin
                  inc(top);
                  xx[top]:=hh;
                  yy[top]:=ll;
                  f[hh,ll]:=true;
                  f[ll,hh]:=true;
               end;
end;

//---------check-----------
procedure check;
var
   hh,ll:longint;

begin
   hh:=max(h[1],max(h[2],max(h[3],h[4])));
   ll:=l[1]+l[2]+l[3]+l[4];
   up(hh,ll);

   hh:=max(h[1],max(h[2],h[3]))+h[4];
   ll:=max(l[4],l[1]+l[2]+l[3]);
   up(hh,ll);

   hh:=max(h[3],max(h[1]+h[4],h[2]+h[4]));
   ll:=max(l[3]+l[4],l[1]+l[2]+l[3]);
   up(hh,ll);

   hh:=max(h[1],max(h[4],h[2]+h[3]));
   ll:=max(l[1]+l[2]+l[4],l[1]+l[4]+l[3]);
   up(hh,ll);

   hh:=max(h[1]+h[3],h[2]+h[4]);
   if h[3]>=h[2]+h[4] then ll:=max(l[1],l[3]+max(l[2],l[4]))
      else
         if (h[3]>h[4]) and (h[3]<h[2]+h[4]) then ll:=max(l[1]+l[2],max(l[2]+l[3],l[3]+l[4]))
         else
            if (h[4]>h[3]) and (h[4]<h[1]+h[3]) then ll:=max(l[1]+l[2],max(l[1]+l[4],l[3]+l[4]))
            else
               if h[4]>=h[1]+h[3] then ll:=max(l[2],max(l[1]+l[4],l[3]+l[4]))
                  else ll:=max(l[1]+l[2],l[3]+l[4]);
   up(hh,ll);
end;

//----------run------------
procedure run(dp:longint);
begin
   if dp>4 then
      begin
         check;
         exit;
      end;
   l[dp]:=x[q[dp]]; h[dp]:=y[q[dp]]; run(dp+1);
   l[dp]:=y[q[dp]]; h[dp]:=x[q[dp]]; run(dp+1);
end;

//-----------qs------------
procedure qs(s,t:longint);
var
   i,j,ce,tmp:longint;

begin
   i:=s; j:=t; ce:=xx[(i+j)>>1];
   repeat
      while xx[i]<ce do inc(i);
      while xx[j]>ce do dec(j);
      if i<=j then
         begin
            tmp:=xx[i]; xx[i]:=xx[j]; xx[j]:=tmp;
            tmp:=yy[i]; yy[i]:=yy[j]; yy[j]:=tmp;
            inc(i); dec(j);
         end;
   until i>j;
   if i<t then qs(i,t); if s<j then qs(s,j);
end;

//----------main-----------
begin
   assign(input,'packrec.in'); reset(input);
   assign(output,'packrec.out'); rewrite(output);
   for i:=1 to 4 do readln(x[i],y[i]);
   ans:=maxlongint;
   for i1:=1 to 4 do
      for i2:=1 to 4 do
         for i3:=1 to 4 do
            for i4:=1 to 4 do
               if (i1<>i2) and (i1<>i3) and (i1<>i4) and
                  (i2<>i3) and (i2<>i4) and (i3<>i4) then
                     begin
                        q[1]:=i1; q[2]:=i2;
                        q[3]:=i3; q[4]:=i4;
                        run(1);
                     end;
   qs(1,top);
   writeln(ans);
   for i:=1 to top do writeln(xx[i],'':1,yy[i]);
   close(input); close(output);
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值