1 条题解

  • 0
    @ 2026-10-26 23:48:26

    思路与算法

    k<4至多三个互不接触的轴平行覆盖矩形,枚举坐标间切线,把最优三矩形化为一矩形加最优二矩形;前后缀包围盒求每个切分面积。

    正确性说明

    对三个两两不相交的轴平行矩形,若x投影交叠图不连通,就存在竖向分离线;否则x交叠图至少含两条边,对应矩形的y投影必须分离,使三点的y交叠图不连通,故有横向分离线。二矩形也必可沿某轴分离。因此枚举第一条线及其中一侧的第二条线覆盖所有最优方案;固定组内点的最小矩形为包围盒,所求面积可精确由前后缀极值计算。

    复杂度

    O(n² log n)时间、O(n)额外空间(各次二分排序与包围盒数组);输入及初始化线性。

    易错点

    切线只能在相邻不同坐标之间,保证边界不相接。允许面积0,少于k个有效矩形时可补不覆盖点的零面积矩形而不改变面积。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using P = pair<int, int>;
    int area(const vector<P> &p) {
        if (p.empty())
            return 0;
        int a = 501, b = -1, c = 501, d = -1;
        for (auto v : p) {
            a = min(a, v.first);
            b = max(b, v.first);
            c = min(c, v.second);
            d = max(d, v.second);
        }
        return (b - a) * (d - c);
    }
    int two(vector<P> p) {
        int n = p.size(), ans = area(p);
        for (int axis = 0; axis < 2; axis++) {
            sort(p.begin(), p.end(), [&](P a, P b) {
                return axis ? a.second < b.second : a.first < b.first;
            });
            vector<int> L(n), R(n);
            int a = 501, b = -1, c = 501, d = -1;
            for (int i = 0; i < n; i++) {
                a = min(a, p[i].first);
                b = max(b, p[i].first);
                c = min(c, p[i].second);
                d = max(d, p[i].second);
                L[i] = (b - a) * (d - c);
            }
            a = c = 501;
            b = d = -1;
            for (int i = n - 1; i >= 0; i--) {
                a = min(a, p[i].first);
                b = max(b, p[i].first);
                c = min(c, p[i].second);
                d = max(d, p[i].second);
                R[i] = (b - a) * (d - c);
            }
            for (int i = 1; i < n; i++)
                if ((axis ? p[i - 1].second : p[i - 1].first) != (axis ? p[i].second : p[i].first))
                    ans = min(ans, L[i - 1] + R[i]);
        }
        return ans;
    }
    int main() {
        int n, k;
        cin >> n >> k;
        vector<P> p(n);
        for (auto &v : p)
            cin >> v.first >> v.second;
        int ans = area(p);
        if (k >= 2)
            ans = two(p);
        if (k == 3)
            for (int axis = 0; axis < 2; axis++) {
                sort(p.begin(), p.end(), [&](P a, P b) {
                    return axis ? a.second < b.second : a.first < b.first;
                });
                for (int i = 1; i < n; i++)
                    if ((axis ? p[i - 1].second : p[i - 1].first) !=
                        (axis ? p[i].second : p[i].first)) {
                        vector<P> a(p.begin(), p.begin() + i), b(p.begin() + i, p.end());
                        ans = min(ans, min(area(a) + two(b), two(a) + area(b)));
                    }
            }
        cout << ans << "\n";
    }
    
    • 1

    信息

    ID
    1925
    时间
    1000ms
    内存
    64MiB
    难度
    普及
    标签
    递交数
    0
    已通过
    0
    上传者