题目大意
求一个面积最小的矩形使其能容纳给定的n个矩形,这n个矩形在该矩形内不能有交,且不能旋转或翻转。
搜索
我们知道——最终方案中,不会存在任何一个矩形可以向左或向上移动。
也就是它们都是贴着的。
于是我们可以定义关键横坐标,初始时只有1,每加入一个矩形,就将其右边界往右一格所在设为关键横坐标。我们规定矩形的左边界必须在关键横坐标上,于是可以知道符合这个规则最后矩形都是贴在一起的。
那么每次枚举要放哪一个矩形,再枚举放在哪个关键横坐标上,接着我们需要二分其放在哪个纵坐标上,需要满足在合法的情况下使这个纵坐标最小,至于判定直接枚举已经放了的矩形看会不会撞。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int w[10],h[10],a[30],b[10][3];
int i,j,k,l,t,n,m,ans,sum,num,top,tot;
bool czy,bz[10];
bool check(int nx,int ny,int W,int H){
int i;
fo(i,1,tot)
if (!(b[i][1]>nx+W-1||b[i][1]+w[b[i][0]]-1<nx||b[i][2]>ny+H-1||b[i][2]+h[b[i][0]]-1<ny)) return 0;
return 1;
}
void dfs(int x){
int i,j,k,l,r,mid,xx=0,yy=0;
fo(i,1,tot) xx=max(xx,b[i][1]+w[b[i][0]]-1),yy=max(yy,b[i][2]+h[b[i][0]]-1);
if (xx*yy>=ans) return;
if (!x){
ans=xx*yy;
return;
}
fo(i,1,n)
if (!bz[i]){
bz[i]=1;
fo(j,1,top){
l=1;r=yy+1;
while (l<r){
mid=(l+r)/2;
if (check(a[j],mid,w[i],h[i])) r=mid;else l=mid+1;
}
b[++tot][0]=i;
b[tot][1]=a[j];
b[tot][2]=l;
a[++top]=a[j]+w[i];
dfs(x-1);
tot--;
top--;
}
bz[i]=0;
}
}
int main(){
freopen("rectangle.in","r",stdin);freopen("rectangle.out","w",stdout);
scanf("%d",&n);
czy=1;
fo(i,1,n){
scanf("%d%d",&w[i],&h[i]);
sum+=w[i];
num+=h[i];
if (w[i]!=1) czy=0;
}
ans=sum*num;
a[top=1]=1;
dfs(n);
printf("%d\n",ans);
}