[BZOJ]1052 覆蓋問題(HAOI2007)

  三矩形覆蓋問題啊……不過據說FJOI還出過雙圓覆蓋問題?node

Description

  某人在山上種了N棵小樹苗。冬天來了,溫度急速降低,小樹苗脆弱得不堪一擊,因而樹主人想用一些塑料薄膜把這些小樹遮蓋起來,通過一番長久的思考,他決定用3個L*L的正方形塑料薄膜將小樹遮起來。咱們不妨將山創建一個平面直角座標系,設第i棵小樹的座標爲(Xi,Yi),3個L*L的正方形的邊要求平行與座標軸,一個點若是在正方形的邊界上,也算做被覆蓋。固然,咱們但願塑料薄膜面積越小越好,即求L最小值。

Input

  第一行有一個正整數N,表示有多少棵樹。接下來有N行,第i+1行有2個整數Xi,Yi,表示第i棵樹的座標。

Output

  一行,輸出最小的L值。spa

Sample Input

  4
  0 1
  0 -1
  1 0
  -1 0code

Sample Output

  1blog

HINT

  1 <= N <= 20000,座標絕對值 <= 10^9,保證不會有2棵樹的座標相同。ip

 

Solution

  三正方形有些複雜,咱們不如先從單正方形,雙正方形入手。單正方形的答案就是max(橫座標極差,縱座標極差)。get

  雙正方形很差貪心,因此咱們二分一下答案,判斷兩個正方形可否覆蓋全部點。string

  咱們就思考一下,這兩個正方形放在哪裏,才能儘可能覆蓋全部點。it

  發現覆蓋的形式不外乎兩種狀況,一種是 一個在左上一個在右下 ,另外一種是 一個在右上一個在左下。io

  假設是 一個在左上一個在右下 的狀況,處於左上方的正方形必定要蓋住橫座標最左的和縱座標最上的點,由於另外一個正方形不會幫你幹這件事。ast

  同理,處於右下方的正方形也同樣。

  因此,兩個正方形放置的位置也就肯定了,剩下的事情就是O(n)掃一遍判斷是否在正方形內了。

 

  那麼三正方形其實也是極其相似的作法。

  仍是二分答案,考慮三個正方形的放法,發現狀況有一點多。

  可是有一點必定是不變的,那就是一定有一個正方形,處於左上、右上、左下、右下的其中一個角!

  那麼咱們就枚舉這個角,刪去這個角內的點,剩下的,就是一個雙正方形覆蓋問題!

  時間複雜度O(nlogn)。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define MN 20005
#define INF 0x3FFFFFFF
using namespace std;
struct node{int x,y;}a[MN];
int b[MN];
int bin,n,L,R;

inline int read()
{
    int n=0,f=1; char c=getchar();
    while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
    while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();}
    return n*f;
}

bool cov(int len)
{
    if (!bin) return true;
    register int i,lm,rm,dm,um;
    lm=dm=INF; rm=um=-INF;
    for (i=1;i<=bin;++i)
        lm=min(lm,a[b[i]].x),rm=max(rm,a[b[i]].x),
        dm=min(dm,a[b[i]].y),um=max(um,a[b[i]].y);
    for (i=1;i<=bin;++i)
        if (!(a[b[i]].x<=lm+len&&a[b[i]].y<=dm+len
            ||a[b[i]].x>=rm-len&&a[b[i]].y>=um-len)) break;
    if (i>bin) return true;
    for (i=1;i<=bin;++i)
        if (!(a[b[i]].x<=lm+len&&a[b[i]].y>=um-len
            ||a[b[i]].x>=rm-len&&a[b[i]].y<=dm+len)) break;
    if (i>bin) return true;
    return false;
}

void del(int lm,int dm,int rm,int um)
{
    register int i;
    for (bin=0,i=1;i<=n;++i)
        if (a[i].x<lm||a[i].x>rm||a[i].y<dm||a[i].y>um) b[++bin]=i;
}

int main()
{
    register int i,lm,rm,dm,um;
    lm=dm=INF; rm=um=-INF;
    n=read();
    for (i=1;i<=n;++i)
        a[i].x=read(),a[i].y=read(),
        lm=min(lm,a[i].x),rm=max(rm,a[i].x),
        dm=min(dm,a[i].y),um=max(um,a[i].y);
    L=0; R=max(um-dm,rm-lm);
    while (L<R)
    {
        int mid=L+R>>1;
        for (i=1;i<=4;++i)
        {
                 if (i==1) del(lm,dm,lm+mid,dm+mid);
            else if (i==2) del(lm,um-mid,lm+mid,um);
            else if (i==3) del(rm-mid,dm,rm,dm+mid);
            else if (i==4) del(rm-mid,um-mid,rm,um);
            if (cov(mid)) break;
        }
        if (i<=4) R=mid; else L=mid+1;
    }
    printf("%d",L);
}

 

Last Word

  沒有想到小C能搶到這題的一個rank1,先放張圖留念,指不定哪天就被某大神艹下去了。

    

相關文章
相關標籤/搜索