题目
思路
本题的关键就在于枚举的技巧和离散化。
1.离散化:对于一个最大的正方形,其必然至少有两条边上有点,因为没有的话还可以继续扩展。这样就直接将题目给的10000x10000的数据范围离散到了100个树。
2.技巧枚举:枚举正方形对边而不是起始点和边长。首先枚举上边和下边,最后枚举左边和右边。注意枚举左边和右边时,只需在已找到上边下边范围内,找黑点作为分隔符,随后分割成几部分就有几个矩形。
3.对于技巧枚举的总结:通过先枚举和部分枚举,原则:
①可由已枚举量得未枚举量。
②部分枚举的量由题设限制,降低了枚举量。
代码
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <set>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
using namespace std;
const int maxn = 10000 + 100;
struct Point {
int x, y;
}A[maxn];
int n, W, H;
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &W, &H);
_for(i, 0, n) scanf("%d%d", &A[i].x, &A[i].y);
int ans = 0, ansx, ansy;
set<int> ycand; // 去重排序的y坐标集合,用于确定上下边
_for(i, 0, n) ycand.insert(A[i].y);
ycand.insert(0); ycand.insert(H);
for (set<int>::iterator ledge = ycand.begin(); ledge != ycand.end(); ++ledge) // 下面的边
for (set<int>::iterator hedge = ledge; hedge != ycand.end(); ++hedge) { // 上面的边
if (ledge == hedge) ++hedge;
if (hedge == ycand.end()) break;
set<int> xcand; // 去重排序x坐标集合,用于确定左右边
_for(i, 0, n)
if (A[i].y < *hedge && A[i].y > *ledge) {
xcand.insert(A[i].x);
}
xcand.insert(0); xcand.insert(W);
set<int>::iterator lastone = xcand.end(); --lastone;
for (set<int>::iterator xledge = xcand.begin(); xledge != lastone; ++xledge) {
set<int>::iterator xredge = xledge;
++xredge;
int heng = abs(*xledge - *xredge), shu = abs(*hedge - *ledge);
int len = min(heng, shu);
if (len > ans) {
ans = len;
ansx = *xledge;
ansy = *ledge;
}
}
}
printf("%d %d %d\n", ansx, ansy, ans);
if (T) printf("\n");
}
return 0;
}
废话
气死了,写完了忘删freopen,上去提交WA,然后还写了个对拍,折腾了将近半个多小时,最后才发现仅仅是没删freopen。