原题: https://www.luogu.org/problemnew/show/P1578

题意:

n*m的矩阵,有几个点(不是格子而是坐标点),问最大的没有覆盖这些点的矩阵。

解析:

首先搞清楚模型,(1,1)和(4,4)是右边的情况,因为给出的案例下面两种答案都是80。
P1578 奶牛浴场(悬线 极大值)
这题虽然不能用悬线法(矩阵太大不可能枚举点)来做,但是可以用类似悬线的思想来做。

对答案子矩阵进行分析,四个边,如果没有被约束,则会往外扩展。所以,四个边一定被障碍点或大矩形边界约束,这个就有点极大的意思在里面了。

先按x值排序。
以一个点作为左边界,尽可能的往右延伸。遇到障碍点时调整上下界继续延伸。

P1578 奶牛浴场(悬线 极大值)
考虑到右边界,需要用if判断或将大矩阵的右上和右下放入点集。

但是考虑不到下图中的情况,所以需要以每个点为右边界,做一遍往左延伸。
P1578 奶牛浴场(悬线 极大值)
最后一种横穿的情况,只需要再次按y值排序遍历即可。
P1578 奶牛浴场(悬线 极大值)
有几个剪枝:

  1. 往右延伸的时候,假设按照当前的上下界,即使延伸到右边界都不能超过答案就break;
  2. 如果遇到和初始点相同的y值时,按理来说会被分解成两个矩形。但是这两个矩形可以证明一定会被除当前搜索外的情况下考虑。下图中,红色部分在右边界障碍点的左延中被考虑,黄色部分在最后按y值排序中,会得到比之更大的解。

P1578 奶牛浴场(悬线 极大值)

AC代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 5005;
int n, m;
struct node {
    int x, y;
    bool operator <(const node &rhs)const {
        return x < rhs.x;
    }
} e[N];
bool cmp(const node &a, const node &b) {
    return a.y < b.y;
}
int main() {
    scanf("%d%d", &n, &m);
    int c;
    scanf("%d", &c);
    for(int i = 1; i <= c; i++) {
        scanf("%d%d", &e[i].x, &e[i].y);
    }
    e[++c].x = 0, e[c].y = 0;
    e[++c].x = n, e[c].y = 0;
    e[++c].x = n, e[c].y = m;
    e[++c].x = 0, e[c].y = m;
    sort(e + 1, e + 1 + c);

    int ans = 0, u, d, l, r;
    for(int i = 1; i <= c; i++) {
        u = m, d = 0, l = e[i].x;
        for(int j = i + 1; j <= c; j++) {
            r = e[j].x;
            ans = max(ans, (r - l) * (u - d));
            if(e[j].y == e[i].y) // 同y值
                break;
            if(e[j].y < u && e[j].y > d) { // 调整上下界
                if(e[j].y > e[i].y)
                    u = e[j].y;
                else
                    d = e[j].y;
            }
            if((u - d) * (n - l) <= ans) // 不能得到更优解
                break;
        }

        u = m, d = 0, r = e[i].x;
        for(int j = i - 1; j >= 1; j--) {
            l = e[j].x;
            ans = max(ans, (r - l) * (u - d));
            if(e[j].y == e[i].y)
                break;
            if(e[j].y < u && e[j].y > d) {
                if(e[j].y > e[i].y)
                    u = e[j].y;
                else
                    d = e[j].y;
            }
            if((u - d) * (r - 0) <= ans)
                break;
        }
    }
    sort(e + 1, e + 1 + c, cmp);
    for(int i = 1; i < c; i++) {
        ans = max(ans, (e[i + 1].y - e[i].y) * n);
    }
    printf("%d\n", ans);
}

相关文章: