Hdu5128 - The E-pang Palace
题意:给定n个点,要求从这n个点当中选择8个点作为顶点来构成2个不相交(不能有任何一个点公共)的矩形,如果无法选出两个这样的矩形的话输出imp,否则输出这两个矩形的最大的面积和。
分析:最容易想到的就是预处理出所有的矩形,假设有n个矩形,之后n*n跑一遍,但这样可能达到C(30,4)*C(30,4)的复杂度,会超时。其实没必要,类似于折半枚举(双向搜索)的思想,只要枚举矩形的两个对角点即两个点就行了,然后判断另外两个点是否存在即可。所以枚举量最多只有C(30,4)了。而且判断两个矩形是否相交的话我们不需要分类出所有的情况,从反面考虑,如果一个矩形在另一个矩形的上方或者左方或者下方或者右方的话就说明不相交了。而且另外一点是,对于一个矩形,我们只需要枚举一次对角顶点的组合,另外一个组合没必要枚举,这样减少了很多不必要的枚举。而且对于选出的4个点,按照x从左从左至右排列假设为a,b,c,d四个点的话,只有3种组合方式(a,b)与(c,d),(a,c)与(b,d),(a,d)与(b,c),全部枚举一下就好了。为方便判断,可以事先给坐标排序,之后枚举所有大小为4的子集,并且每次对3种组合方式判断一下取最大值。
这题的一个坑点:一个矩形可能完全包含在另一个矩形中,这种情况下面积取较大者,否则取和。
暴力枚举不失为一种好办法,但是过多的枚举必然会导致效率低下了。所以下手之前可以分析下,看是否可以减少重复的没必要的枚举,而且有时候减少这些枚举还可以保证正确率,就像这题如果枚举矩形的两个对角的组合的话可能会导致判断不全面导致计算错误,之前做的时候就是这样,发现答案变大了,原因是因为考虑不全面,但是其实是没必要的。而且折半枚举也是一种重要的思想,因为很多情况下只需要枚举一部分量,然后另一部分量直接判断或者进行查找就好了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
struct po{
int x, y;
bool operator < (const po& a) const{
return x == a.x ? y < a.y : x < a.x;
}
}p[50];
int vis[210][210];
int check(int i, int j, int k, int l)
{
int ix = p[i].x, iy = p[i].y, jx = p[j].x, jy = p[j].y;
int kx = p[k].x, ky = p[k].y, lx = p[l].x, ly = p[l].y;
if (ix == jx || iy >= jy || kx == lx || ky >= ly) return 0;
if (!vis[ix][jy] || !vis[jx][iy] || !vis[kx][ly] || !vis[lx][ky]) return 0;
if (jx < kx || ix > lx || jy < ky || iy > ly) return (jx - ix) * (jy - iy) + (lx - kx) * (ly - ky);
if (ix < kx && kx < jx && ix < lx && lx < jx && iy < ky && ky < jy && iy < ly && ly < jy) return (jx - ix) * (jy - iy);
return 0;
}
int solve(int i, int j, int k, int l)
{
return max(check(i, j, k, l), max(check(i, k, j, l), check(i, l, j, k)));
}
int main()
{
int n;
while (scanf("%d", &n), n){
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++) scanf("%d %d", &p[i].x, &p[i].y), vis[p[i].x][p[i].y] = 1;
if (n < 8) { puts("imp"); continue; }
sort(p, p + n);
int k = (1 << 4) - 1;
int ans = 0;
while (k < 1 << n){
int t[4];
for (int i = 0, j = 0; i < n; i++)
if (k & (1 << i)) t[j++] = i;
ans = max(ans, solve(t[0], t[1], t[2], t[3]));
int x = k & -k, y = k + x;
k = ((k & ~y) / x >> 1) | y;
}
ans ? printf("%d\n", ans) : puts("imp");
}
return 0;
}