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
", kase, work());
}

int main()
{
    while (scanf("%d", &n) && n) solve();
    return 0;
} 
原文地址:https://www.cnblogs.com/yohanlong/p/7703994.html