// Chainsaw Massacre (电锯惊魂) // PC/UVa IDs: 111403/10043, Popularity: B, Success rate: low Level: 3 // Verdict: Accepted // Submission Date: 2011-11-14 // UVa Run Time: 0.196s // // 版权所有(C)2011,邱秋。metaphysis # yeah dot net // // [解题方法] // 目标是 O(n^2)的算法,否则容易 TLE。本质是找最一个内部为空的长方形,那么可以依次以一棵数作为 // 左边界,往右扫描确定右边界,当左右边界确定后,就可以确定其面积,然后上下再进行一次同样的扫描,即 // 可确定最终的最大矩形面积。 #include <iostream> #include <algorithm> using namespace std; #define MAXTREES 2500 // 虽然题意是最多只有 1000 棵树,但是可能会有重复的坐标。 struct tree { int x; int y; }; tree trees[MAXTREES]; int l, w; bool cmpXY(tree a, tree b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } bool cmpX(tree a, tree b) { return a.x < b.x; } bool cmpY(tree a, tree b) { return a.y < b.y; } int main(int ac, char *av[]) { int cases, total; int k, x, y, dx, dy; cin >> cases; while (cases--) { // 注意左边界的处理,可以将有树的行的左边界置为有树。 cin >> l >> w; // 左上角和右下角的可以先 “种” 树,因为矩形可能以此为边界。 total = 0; trees[total++] = (tree){0, 0}; trees[total++] = (tree){l, w}; // 读取数据。 while (cin >> k, k) { if (k == 1) { cin >> x >> y; trees[total++] = (tree){x, y}; } else { cin >> x >> y >> dx >> dy; for (int i = 1; i <= k; i++) trees[total++] = (tree){x + (i - 1) * dx, y + (i - 1) * dy}; } } // 去除重复的坐标,可用可不用,用的话可以减少点运行时间,不用,不影响结果。用 // 快速排序是否可以将时间减得更少?没有尝试过,加上去重复的代码 RT 在 UVa 排 // 第 35 位。用 map 来表示坐标是否更快?有空试试看能不能进到前 10 位。 // sort(trees, trees + total, cmpXY); // int hole = 1, oldTotal = total; // for (int i = 1; i < oldTotal; i++) // if (trees[hole - 1].x == trees[i].x && trees[hole - 1].y == trees[i].y) // total--; // else // trees[hole++] = trees[i]; // 对于每一棵树,以其作为矩形的左边界,往右扫描,直到发现某一列有树,或者达到右 // 侧边界,则该列为此矩形的右边界。先按横坐标进行排序。 int maxArea = 0, lowY, topY, leftX, rightX; sort(trees, trees + total, cmpX); for (int i = 0; i < total; i++) { lowY = 0; topY = w; for (int j = i + 1; j < total; j++) { if (trees[j].x == trees[i].x) continue; else { maxArea = max(maxArea, (trees[j].x - trees[i].x) * (topY - lowY)); if (trees[j].y < trees[i].y) lowY = max(lowY, trees[j].y); else topY = min(topY, trees[j].y); } } } // 先确定上界,再确定下界,再确定矩形,先按纵坐标排序。 sort(trees, trees + total, cmpY); for (int i = 0; i < total; i++) { leftX = 0; rightX = l; for (int j = i + 1; j < total; j++) { if (trees[j].y == trees[i].y) continue; else { maxArea = max(maxArea, (trees[j].y - trees[i].y) * (rightX - leftX)); if (trees[j].x < trees[i].x) leftX = max(leftX, trees[j].x); else rightX = min(rightX, trees[j].x); } } } cout << maxArea << endl; } return 0; }