uva3695
题意是给出平面上的n个点,找一个矩形使得边界上包含的点最多。
Sol
经典套路是减小枚举的范围。
最暴力的方法是枚举四条边界然后O(n)判断,一共的时间复杂度是O(n5)。
优化的方法是只枚举矩形的上下边界,用奇技淫巧确定左右边界。(一种类似前缀和的思想)
枚举完上下边界之后只需要O(n)扫一遍处理好三个数组,之后再以类似uva11078的思路O(n)求解。
时间复杂度O(n3)
对于上下边界的枚举,我们可以先处理出存储y信息的数组,之后对该数组进行去重,如此大大方便了上下边界的枚举。
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 105; int n, kase; int on[maxn], on2[maxn], left[maxn], y[maxn]; struct point { int x, y; bool operator < (const point& rhs) const { return x < rhs.x; } }p[maxn]; int work() { for (int i = 1; i <= n; i++) { scanf("%d%d", &p[i].x, &p[i].y); y[i] = p[i].y;//套路 } sort(p + 1, p + 1 + n); sort(y + 1, y + 1 + n); int m = unique(y + 1, y + n + 1) - y - 1; if (m <= 2) { return n; } int ans = 0; for (int a = 1; a < m; a++) for (int b = a + 1; b <= m; b++) { int ymin = y[a], ymax = y[b]; int k = 0; for (int i = 1; i <= n; i++) { if (i == 1 || p[i].x != p[i - 1].x)//出现了一条新的竖线 { k++; on[k] = on2[k] = 0;//相当于初始化on[],on2[] left[k] = left[k - 1] + on2[k - 1] - on[k - 1];//用上一个left递推现在这个left } if (p[i].y > ymin && p[i].y < ymax) on[k]++; if (p[i].y >= ymin && p[i].y <=ymax) on2[k]++; } if (k <= 2) { return n; } int mx = 0;//uva11078的思路 for (int j = 1; j <= k; j++) { ans = max(ans, left[j] +on2[j] + mx); mx = max(mx, on[j] - left[j]); } } return ans; } void solve() { kase++; printf("Case %d: %d\n", kase, work()); } int main() { while (scanf("%d", &n) && n) solve(); return 0; }