给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠。所谓最小矩形指该矩形面积最小。
图1 四个矩形的六个基本布局
4个矩形块中任一个矩形的边都与封闭矩形的边相平行,图1显示出了铺放4个矩形块的6种方案。这6种方案是唯一可能的基本铺放方案。因为其它方案能由基本方案通过旋转和镜像反射得到。
可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长。
下面是一个分析,对每种布局有很清楚的解释:http://hi.baidu.com/readd123/item/f7c57925d963ab0872863e82
//下面的部分来自上述博客
只要找准几种状态就行了,题目中的6个已经足够了,举每个方块的选择顺序和放置方向就行了。
第4、5个在本质上其实是一样。如图,不同模式对应的最小面积如下:
设w1,w2,w3,w4表示4个方块的横长,h1,h2,h3,h4表示4个方块的纵长。w,h表示最小。
1:w=w1+w2+w3+w4;h=max(h1,h2,h3,h4)
2:w=max(w1+w2+w3,w4);h=max(h1,h2,h3)+h4
3:w=max(w1+w2,w3)+w4;h=max(h1+h3,h2+h3,h4)
4:w=w1+w2+max(w3,w4);h=max(h1,h3+h4,h2)
5:h=max(h1+h3,h2+h4)
对于w,我们细分为如下四种形式:
(1):h3>=h2+h4;w=max(w1,w3+w2,w3+w4)
(2):h3>h4 and h3<h2+h4;w=max(w1+w2,w2+w3,w3+w4) // 要理解这两条w是如何计算出来的。
(3):h4>h3 and h4<h1+h3;w=max(w1+w2,w1+w4,w3+w4) //
(4):h4>=h1+h3;w=max(w2,w1+w4,w3+w4)
*:h3=h4(图中没画);w=max(w1+w2,w3+w4)
之后便是具体实现了:
/*
ID: wuqi9395@126.com
PROG: packrec
LANG: C++
*/
//http://hi.baidu.com/readd123/item/f7c57925d963ab0872863e82
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000
#define INF 1<<25
#define mem(a, b) memset(a, b, sizeof(a))
#define For(i, n) for (int i = 0; i < n; i++)
typedef long long ll;
using namespace std;
struct node {
int x, y;
}e[10];
int mn = INF, h, w;
int next[10] = {0}, inx = 0;
node in[10], tmp, out[maxn];
bool cmp(node s, node v) {
return s.x < v.x;
}
void pack1() {
h = 0, w = 0;
for (int i = 0; i < 4; i++) {
h = max(h, in[i].y);
w += in[i].x;
}
tmp.x = min(w, h);
tmp.y = max(w, h);
if (w * h < mn) {
inx = 0;
out[inx++] = tmp;
mn = w * h;
}
else if (w * h == mn) {
out[inx++] = tmp;
}
}
void pack2() {
h = w = 0;
for (int i = 0; i < 3; i++) {
h = max(h, in[i].y);
w += in[i].x;
}
h += in[3].y;
w = max(w, in[3].x);
tmp.x = min(w, h);
tmp.y = max(w, h);
if (w * h < mn) {
inx = 0;
out[inx++] = tmp;
mn = w * h;
}
else if (w * h == mn) {
out[inx++] = tmp;
}
}
void pack3() {
h = w = 0;
h = max(max(in[0].y, in[1].y) + in[3].y, in[2].y);
w = max(in[0].x + in[1].x, in[3].x) + in[2].x;
tmp.x = min(w, h);
tmp.y = max(w, h);
if (w * h < mn) {
inx = 0;
out[inx++] = tmp;
mn = w * h;
}
else if (w * h == mn) {
out[inx++] = tmp;
}
}
void pack4() {
h = w = 0;
h = max(max(in[0].y + in[1].y, in[2].y), in[3].y);
w = max(in[0].x, in[1].x) + in[2].x + in[3].x;
tmp.x = min(w, h);
tmp.y = max(w, h);
if (w * h < mn) {
inx = 0;
out[inx++] = tmp;
mn = w * h;
}
else if (w * h == mn) {
out[inx++] = tmp;
}
}
void pack5() {
h = max(in[0].y + in[1].y, in[2].y + in[3].y);
if (in[1].y >= in[2].y + in[3].y) w = max(max(in[2].x, in[3].x) + in[1].x, in[0].x);
if (in[1].y > in[3].y && in[1].y < in[2].y + in[3].y) w = max(max(in[0].x + in[2].x, in[2].x + in[1].x), in[1].x + in[3].x); // 怎么改了这个就对了。。 之前是max(in[0].x, in[1].x) + max(in[2].x, in[3].x);
if (in[0].y + in[1].y >= in[3].y && in[1].y < in[3].y) w = max(max(in[0].x + in[2].x, in[0].x + in[3].x), in[1].x + in[3].x); //同上
if (in[0].y + in[1].y <= in[3].y) w = max(max(in[0].x, in[1].x) + in[3].x, in[2].x);
if (in[1].y == in[3].y) w = max(in[0].x + in[2].x, in[1].x + in[3].x);
tmp.x = min(w, h);
tmp.y = max(w, h);
if (w * h < mn) {
inx = 0;
out[inx++] = tmp;
mn = w * h;
}
else if (w * h == mn) {
out[inx++] = tmp;
}
}
int main ()
{
freopen ("packrec.in", "r", stdin);
freopen ("packrec.out", "w", stdout);
for (int i = 0; i < 4; i++) {
scanf("%d%d", &e[i].x, &e[i].y);
e[i + 4].x = e[i].y;
e[i + 4].y = e[i].x;
next[i] = i;
}
do {
int tot = 1 << 4;
for (int i = 0; i < tot; i++) {
for (int j = 0; j < 4; j++) {
if ((i >> j) & 1) in[j] = e[next[j]];
else in[j] = e[next[j] + 4];
}
pack1();
pack2();
pack3();
pack4();
pack5();
}
} while(next_permutation(next, next + 4));
cout<<mn<<endl;
sort(out, out + inx, cmp);
cout<<out[0].x<<" "<<out[0].y<<endl;
for (int i = 1; i < inx; i++) if (out[i].x != out[i - 1].x)
cout<<out[i].x<<" "<<out[i].y<<endl;
return 0;
}
[USACO Section 1.4] Packing Rectangles (模拟)
原文:http://blog.csdn.net/sio__five/article/details/19699283