[HAOI2007] 覆盖问题 - 二分,贪心,DFS

给定平面上若干点,用三个等大的正方形去覆盖(在边界上也算被覆盖),边平行于坐标轴,求最小边长。\(n \leq 20000\)

Solution

为什么是三个矩形?

  • 对于 \(k\) 个矩形的覆盖方案,至少各有一个矩形与四条边界重合

而当 \(k\leq3\) 时,如果每个矩形都恰好只沾了一条边界,那么与上述引理矛盾,因此

  • 对于 \(k \leq 3\) 个矩形的覆盖方案,至少有一个矩形与边界矩形的一个角重合

因此,考虑二分,检验答案时,我们只需要枚举下一个矩形放在哪个角上,然后算出去掉这些点后的边界,并递归做下去即可

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

const int N = 20005;
int n,x[N],y[N],u[N],a;

int dfs(int k) {
    int xl=1e9,xr=-1e9,yl=1e9,yr=-1e9;
    for(int i=1;i<=n;i++) if(u[i]==0) {
        xl=min(xl,x[i]);
        yl=min(yl,y[i]);
        xr=max(xr,x[i]);
        yr=max(yr,y[i]);
    }
    if(k==1) {
        if(xr-xl<=a && yr-yl<=a) return 1;
        return 0;
    }
    else {
        int tmp=0;
        vector <int> v;
        for(int i=1;i<=n;i++) {
            if(xl<=x[i] && x[i]<=xl+a && yl<=y[i] && y[i]<=yl+a && u[i]==0) {
                v.push_back(i);
                u[i]=1;
            }
        }
        tmp = dfs(k-1);
        for(int i=0;i<v.size();i++) u[v[i]]=0;
        v.clear();
        if(tmp) return 1;
        for(int i=1;i<=n;i++) {
            if(xl<=x[i] && x[i]<=xl+a && yr-a<=y[i] && y[i]<=yr && u[i]==0) {
                v.push_back(i);
                u[i]=1;
            }
        }
        tmp = dfs(k-1);
        for(int i=0;i<v.size();i++) u[v[i]]=0;
        v.clear();
        if(tmp) return 1;
        for(int i=1;i<=n;i++) {
            if(xr-a<=x[i] && x[i]<=xr && yl<=y[i] && y[i]<=yl+a && u[i]==0) {
                v.push_back(i);
                u[i]=1;
            }
        }
        tmp = dfs(k-1);
        for(int i=0;i<v.size();i++) u[v[i]]=0;
        v.clear();
        if(tmp) return 1;
        for(int i=1;i<=n;i++) {
            if(xr-a<=x[i] && x[i]<=xr && yr-a<=y[i] && y[i]<=yr && u[i]==0) {
                v.push_back(i);
                u[i]=1;
            }
        }
        tmp = dfs(k-1);
        for(int i=0;i<v.size();i++) u[v[i]]=0;
        v.clear();
        if(tmp) return 1;
    }
    return 0;
}

int check() {
    for(int i=1;i<=n;i++) u[i]=0;
    int tmp=dfs(3);
    return tmp;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
    int l=0,r=2e9;
    while(l<r) {
        a=(l+r)/2;
        if(check()) r=a;
        else l=a+1;
    }
    cout<<l;
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12381768.html