1. 程式人生 > >【題解】覆蓋問題 BZOJ1052 HAOI2007 二分

【題解】覆蓋問題 BZOJ1052 HAOI2007 二分

下一個 bool space efi 然而 names 整數 一行 IE

題目描述

某 人在山上種了N棵小樹苗。冬天來了,溫度急速下降,小樹苗脆弱得不堪一擊,於是樹主人想用一些塑料薄膜把這些小樹遮蓋起來,經過一番長久的思考,他決定用 3個LL的正方形塑料薄膜將小樹遮起來。我們不妨將山建立一個平面直角坐標系,設第i棵小樹的坐標為(Xi,Yi),3個LL的正方形的邊要求平行與坐標 軸,一個點如果在正方形的邊界上,也算作被覆蓋。當然,我們希望塑料薄膜面積越小越好,即求L最小值。

輸入輸出

input
第一行有一個正整數N,表示有多少棵樹。
接下來有N行,第i+1行有2個整數Xi,Yi,表示第i棵樹的坐標,保證不會有2個樹的坐標相同。
output
一行,輸出最小的L值

樣例

input

4 0 1 0 -1 1 0 -1 0

output

1

數據範圍

100%的數據,N<=20000

思路

確定在一定範圍內有一些點,然後用邊長為常數k(<邊界範圍)的三個正方形去覆蓋它們的話,如果有合法的方案,那麽一定存在至少一個正方形,它的兩條邊分別卡在兩個邊界上。
這個性質非常容易證明。因為如果確定是上下左右的邊界,那麽每一個邊界上至少有一個點需要去覆蓋。然而我們只有三個正方形,若想要覆蓋這四個點,一定存在一個正方形覆蓋了兩個點,那麽它就一定卡在兩個邊界上。如果正方形數少的話就更顯然了。
做法:二分出一個答案k,然後dfs判斷。dfs每一次放一個正方形,枚舉它卡著當前區域的哪兩個邊界即可。

代碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>

#define N 22222
#define INF 2147483647

using namespace std;
/*
首先,求出所有點的4個邊界值形成的一個矩形,第一個正方形的一個邊界一定與這個矩形的4個角中的一個重合,枚舉4次即可,
然後再找到剩下的點中的邊界,重復一遍上面的操作,最後判斷一下一個正方形是否可以覆蓋剩余的所有矩形
*/
struct P
{
    int x,y;
}p[N],p1[N],p2[N];

int n;

inline void read()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
}

inline bool check(int len)
{
    if(n==0) return true;
    int sd[4][4];
    sd[1][1]=INF; sd[1][2]=-INF;
    sd[2][1]=INF; sd[2][2]=-INF;
    for(int i=1;i<=n;i++)
    {
        sd[1][1]=min(sd[1][1],p[i].x); sd[1][2]=max(sd[1][2],p[i].x);
        sd[2][1]=min(sd[2][1],p[i].y); sd[2][2]=max(sd[2][2],p[i].y);
    }
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
        {
            int m=0;
            for(int k=1;k<=n;k++)
                if(abs(p[k].x-sd[1][i])>len||abs(p[k].y-sd[2][j])>len) p1[++m]=p[k];
            if(m==0) return true;

            int sp[4][4];
            sp[1][1]=INF; sp[1][2]=-INF;
            sp[2][1]=INF; sp[2][2]=-INF;
            for(int k=1;k<=m;k++)
            {
                sp[1][1]=min(sp[1][1],p1[k].x); sp[1][2]=max(sp[1][2],p1[k].x);
                sp[2][1]=min(sp[2][1],p1[k].y); sp[2][2]=max(sp[2][2],p1[k].y);
            }
            for(int ii=1;ii<=2;ii++)
                for(int jj=1;jj<=2;jj++)
                {
                    int s=0;
                    for(int kk=1;kk<=m;kk++)
                        if(abs(p1[kk].x-sp[1][ii])>len||abs(p1[kk].y-sp[2][jj])>len) p2[++s]=p1[kk];
                    if(s==0) return true;

                    int sq[4][4];
                    sq[1][1]=INF; sq[1][2]=-INF;
                    sq[2][1]=INF; sq[2][2]=-INF;
                    for(int kk=1;kk<=s;kk++)
                    {
                        sq[1][1]=min(sq[1][1],p2[kk].x); sq[1][2]=max(sq[1][2],p2[kk].x);
                        sq[2][1]=min(sq[2][1],p2[kk].y); sq[2][2]=max(sq[2][2],p2[kk].y);
                    }
                    if(sq[2][2]-sq[2][1]<=len&&sq[1][2]-sq[1][1]<=len) return true;
                }
        }
    return false;
}

inline void go()
{
    int l=0,r=2000000000,mid,ans;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}

int main()
{
    read(),go();
    return 0;
}

【題解】覆蓋問題 BZOJ1052 HAOI2007 二分