题目描述
给定 44 个矩形块,找出一个最小的封闭矩形将这 44 个矩形块放入,但不得相互重叠。所谓最小矩形指该矩形面积最小。
44 个矩形块中任一个矩形的边都与封闭矩形的边相平行,上图显示出了铺放 44 个矩形块的 66 种方案。
这 66 种方案是唯一可能的基本铺放方案。因为其它方案能由基本方案通过旋转和镜像反射得到。
可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长。
输入格式
共有 44 行,每行两个正整数,表示每个矩形的边长。
输出格式
总行数为解的总数加一。
第一行是一个整数,代表封闭矩形的最小面积。
接下来的每一行都表示一个解,由 p,q\space (p \leqslant q)p,q (p⩽q) 来表示。这些行必须根据 pp 的大小按升序排列,且所有行都应是不同的。
输入输出样例
输入 #1复制
1 2 2 3 3 4 4 5
输出 #1复制
40 4 10 5 8
说明/提示
【数据范围】
对于 100\%100% 的数据,输入的所有数在 [1,50][1,50] 内。
题目翻译来自NOCOW。
USACO Training Section 1.4
这道题就是暴力搜索题,写一个 DFS 就可以完美解决了,主要是对于各种情况的处理,本蒟蒻将一一讲解。
其实本蒟蒻想不出来这些摆放的情况,但是题目画了图啊 awa。
几种情况的图片:
接下来我们用 a,ba,b 来表示封闭矩阵的宽和长,x1, x2, x3, x4x1,x2,x3,x4 分别表示四个矩阵的宽,y1, y2, y3, y4y1,y2,y3,y4 分别表示四个矩阵的长。
不管这个矩阵怎么歪,我们只把对 aa 的值有贡献的边记作 x_{i}xi,对 bb 有贡献的记作 y_{i}yi。(1 \le i \le 4)(1≤i≤4)。
第一种情况
四种并排放。 很容易可以看出:a = x1 + x2 + x3 + x4a=x1+x2+x3+x4。
bb 的值就为他们中的最大值,所以 b = \max(\max(y1, y2), \max(y3, y4))b=max(max(y1,y2),max(y3,y4))。
第二种情况
三个并排,一个躺平。 也可以得出:a = \max(x1 + x2 + x3, x4)a=max(x1+x2+x3,x4)。
以及:b = \max(y1,\max(y2,y3)) + y4b=max(y1,max(y2,y3))+y4。
第三种情况
显然:a = \max(x1 + x2, x3) + x4a=max(x1+x2,x3)+x4。
b = \max(\max(y1, y2) + y3, y4)b=max(max(y1,y2)+y3,y4)。
第四种情况
看似更复杂,其实就是堆在一起的 2,3 号矩阵难以处理。但细想想也不难,堆在上面的那个的 xx 值一定小于等于下面那个,所以这两个矩阵对于 aa 的值的贡献为:\max(x2, x3)max(x2,x3)。
由此可得:a = x1 + \max(x2, x3) + x4a=x1+max(x2,x3)+x4。
b = \max(y1, \max(y2 + y3, y4))b=max(y1,max(y2+y3,y4))。
第五种情况
与第四种基本相同,区别在于第四种堆叠的矩阵位于中间,第五种位于旁边
显然:a = \max(x1, x2) + x3 + x4a=max(x1,x2)+x3+x4。
b = \max(y1 + y2, \max(y3, y4))b=max(y1+y2,max(y3,y4))。
第六种情况
最复杂的情况,看似复杂实则也很容易懂,要分情况讨论,想必各位神犇做数学题时没少遇到。
我们统一一下编号:右上角,左上角,右下角,左下角,按照这个顺序从 1 到 4 编号。
情况一:y4 + y2 \le y3y4+y2≤y3
各位不妨画个图,立刻就可以得出:a = \max(\max(x1, x3 + x2), x3 + x4)a=max(max(x1,x3+x2),x3+x4)。
情况二:在不满足情况一的条件下,y4 < y3y4<y3
依然可以轻松得出:a = \max(x1 + x2, \max(x2, x4) + x3)a=max(x1+x2,max(x2,x4)+x3)。
情况三:y3 = y4y3=y4
这是所有情况中最直观的:a = \max(x1 + x2, x3 + x4)a=max(x1+x2,x3+x4)。
情况四:y3 < y4y3<y4,且不满足情况五
依然是画了图以后就可以轻松得出:a = \max(x1 + x2, \max(x1, x3) + x4)a=max(x1+x2,max(x1,x3)+x4)。
情况五:y1 + y3 \le y4y1+y3≤y4
动手画图后可以得出:a = \max(x2, \max(x1, x3) + x4)a=max(x2,max(x1,x3)+x4)。
看到这可能有神犇会好奇,bb 咋求?
画图啊,画图一下子就出来了:b = \max(y1 + y3, y2 + y4)b=max(y1+y3,y2+y4)。
代码
具体应该怎么做呢? 先深搜枚举位置(也就是上文中编号),然后调用计算就行了。
非常的简单,就是很肝。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[5][2], num[5]; //分别储存每个矩阵的长宽,顺序
int cnt, Min = INT_MAX;
bool vis[5], flag[402][402];
struct node {
int p, q;
} ans[2050];//结构体排序完成子任务
void answer (int sx, int sy) {
if (sx > sy) swap(sx, sy);//也是子任务
if (flag[sx][sy]) return;//防止重复
flag[sx][sy] = true;
if (sx * sy < Min) {
Min = sx * sy;
cnt = 1;
ans[cnt].p = sx, ans[cnt].q = sy;
} else if (sx * sy == Min) {
ans[++cnt].p = sx;
ans[cnt].q = sy;
}
}
void f (int s1, int s2, int s3, int s4) {
int x, y;
x = a[s1][1] + a[s2][1] + a[s3][1] + a[s4][1], y = max(max(a[s1][0], a[s2][0]), max(a[s3][0], a[s4][0]));
answer(x, y);
x = max(a[s1][1] + a[s2][1] + a[s3][1], a[s4][1]), y = max(a[s1][0], max(a[s2][0], a[s3][0])) + a[s4][0];
answer(x, y);
x = max(a[s1][1] + a[s2][1], a[s3][1]) + a[s4][1], y = max(a[s4][0], max(a[s1][0], a[s2][0]) + a[s3][0]);
answer(x, y);
x = a[s1][1] + max(a[s2][1], a[s3][1]) + a[s4][1], y = max(a[s4][0], max(a[s1][0], a[s2][0] + a[s3][0]));
answer(x, y);
x = max(a[s1][1], a[s2][1]) + a[s3][1] + a[s4][1], y = max(max(a[s1][0] + a[s2][0], a[s3][0]), a[s4][0]);
answer(x, y);
if (a[s3][0] >= a[s2][0] + a[s4][0]) x = max(max(a[s1][1], a[s3][1] + a[s2][1]), a[s3][1] + a[s4][1]);
else if (a[s4][0] < a[s3][0]) x = max(a[s1][1] + a[s2][1], max(a[s2][1], a[s4][1]) + a[s3][1]);
else if (a[s3][0] == a[s4][0]) x = max(a[s1][1] + a[s2][1], a[s3][1] + a[s4][1]);
else if (a[s3][0] < a[s4][0] && a[s4][0] < a[s3][0] + a[s1][0]) x = max(a[s1][1] + a[s2][1], max(a[s1][1], a[s3][1]) + a[s4][1]);
else if (a[s4][0] >= a[s1][0] + a[s3][0]) x = max(a[s2][1], max(a[s1][1], a[s3][1]) + a[s4][1]);
y = max(a[s1][0] + a[s3][0], a[s2][0] + a[s4][0]);
answer(x, y);
}//上文有详细讲,这里不再赘述
void dfs (int k) {
if (k == 5) {
f(num[1], num[2], num[3], num[4]);
return;
}
for (int i = 1; i <= 4; i++) {
if (vis[i]) continue;
vis[i] = true;
num[k] = i;
dfs(k + 1);
swap(a[i][0], a[i][1]);//把矩阵转90°再搜
dfs(k + 1);
swap(a[i][0], a[i][1]);
vis[i] = false;//回溯
}
}
bool cmp (node a, node b) {return a.p < b.p;}
int main () {
for (int i = 1; i <= 4; i++) scanf("%d%d", &a[i][0], &a[i][1]);
dfs(1);
sort(ans + 1, ans + 1 + cnt, cmp);
printf("%d\n", Min);
for (int i = 1; i <= cnt; i++) printf("%d %d\n", ans[i].p, ans[i].q);//完美的输出
return 0;
}
这道题算是绿题中比较简单的了,而且还是一次水两道 awa。