P1212 [USACO1.4] 铺放矩形块 Packing Rectangles
luogu上的那博客是我
题目描述
给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠。所谓最小矩形指该矩面积最小。 4 个矩形块6种方案,这6种方案是唯一可能的基本铺放方案。
读题后我们可以知道这可以用DFS生成一个排列 如下:
void dfs(int ceng)/生成/排列 {
if(ceng == 4) {
check();
return ;
}
for (int i = 1; i < 5; i ++ ) {
if(!vis[i]) {
tmpx[ceng + 1] = x[i];
tmpy[ceng + 1] = y[i];
vis[i] = true;
dfs(ceng + 1);
tmpx[ceng + 1] = y[i];//这里不是tmpx存x了!下一次做的时候 x,y需要反过来
tmpy[ceng + 1] = x[i];//这里不是tmpy存y了!下一次做的时候 x,y需要反过来
dfs(ceng + 1);
vis[i] = false;
tmpx[ceng + 1] = 0;
tmpy[ceng + 1] = 0;
}
}
}
若判断到边界时,即ceng==4时用一个判断check();
如此,我们就可以设a为上下边,b为左右边
第一种情况
很容易可以看出:a = x1 + x2 + x3 + x4
b的值就为他们中的最大值,所以b=max(max(y1,y2),max(y3,y4))。
第二种情况
也可以得出a=max(x1+x2+x3,x4)。
以及:b=max(y1,max(y2,y3))+y4。
第三种情况
显然:a=max(x1+x2,x3)+x4。
b=max(max(y1,y2)+y3,y4)。
第四种情况
堆在上面的那个的 x 值一定小于等于下面那个,所以这两个矩阵a的值为:max(x2,x3)。
由此可得:a=x1+max(x2,x3)+x4。 b=max(y1,max(y2+y3,y4))。
第五种情况
显然:
a = max(x1, x2) + x3 + x4
b=max(y1+y2,max(y3,y4))。
第六种情况(分一下类)
我们统一下编号:右上角,左上角,右下角,左下角,按照这个顺序从 1 到 4 编号。
情况一:y4 + y2 ≤y3
画个图就可以得出:a=max(max(x1,x3+x2),x3+x4)。
情况二:在不满足情况一的条件下,y4 < y3
依然可以轻松得出:a=max(x1+x2,max(x2,x4)+x3)。
情况三:y3=y4
这是所有情况中最直观的:a=max(x1+x2,x3+x4)。
情况四:y3 < y4,且不满足情况五
依然是画了图以后就可以得出:a=max(x1+x2,max(x1,x3)+x4)。
情况五:y1 + y3 ≤y4
画图后可以得出:a=max(x2,max(x1,x3)+x4)。b=max(y1+y3,y2+y4)。
由此便可以得出:
int x, y;
/*
顺序:
1 2 3 4
1 2 3 4
*/
x = tmpx[1] + tmpx[2] + tmpx[3] + tmpx[4];
y = max(max(tmpy[1], tmpy[2]), max(tmpy[3], tmpy[4]));
get_ans(x,y);
/*
顺序:
1 2 3
4 4 4
*/
x = max(tmpx[1] + tmpx[2] + tmpx[3], tmpx[4]);
y = max(tmpy[1], max(tmpy[2], tmpy[3])) + tmpy[4];
get_ans(x,y);
/*
顺序:
1 2 4
3 3 4
*/
x = max(tmpx[1] + tmpx[2], tmpx[3]) + tmpx[4];
y = max(max(tmpy[1], tmpy[2]) + tmpy[3], tmpy[4]);
get_ans(x,y);
/*
顺序:
1 2 4
1 3 4
*/
x = tmpx[1] + max(tmpx[2], tmpx[3]) + tmpx[4];
y = max(tmpy[1], max(tmpy[2] + tmpy[3], tmpy[4]));
get_ans(x,y);
/*
顺序:
1 2
3 4
*/
y = max(tmpy[1] + tmpy[3], tmpy[2] + tmpy[4]);//特判
if (tmpy[1] + tmpy[3] <= tmpy[4]) {
x = max(tmpx[2], max(tmpx[1], tmpx[3]) + tmpx[4]);
} else if (tmpy[3] <= tmpy[4] && tmpy[1] + tmpy[3] >= tmpy[4]) {
x = max(tmpx[1] + tmpx[2], max(tmpx[1], tmpx[3]) + tmpx[4]);
} else if (tmpy[3] >= tmpy[4] && tmpy[3] <= tmpy[2] + tmpy[4]) {
x = max(tmpx[1] + tmpx[2], max(tmpx[2], tmpx[4]) + tmpx[3]);
} else if (tmpy[3] >= tmpy[2] + tmpy[4]) {
x = max(tmpx[1], max(tmpx[2], tmpx[4]) + tmpx[3]);
}
get_ans(x,y);
到了这儿核心就好了; 当dfs生成排列,触碰到了边界就运行它。
对了还有get_ans的标记p当最小面积求出时用其除掉p就是q;
void get_ans(int x,int y) {
if (x * y < ans) {
memset(s, 0, sizeof(s));
ans = x * y;
}
if (x * y == ans) {
s[min(x, y)] = 1;
/*
s[x]=1;
s[y]=1;
*/
}
}
最后就可以如上所说输出即可;
for (int i = 1; i < 5; i ++ ) {
cin >> x[i] >> y[i];
}
dfs(0);
cout << ans << endl;
int k = sqrt(ans);
for (int i = 1; i <= k; i ++ ) {
if(s[i]) {
cout << i << " " << ans / i << endl;
}
}