[题目描述]
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.