BZOJ 1052 覆盖问题

Description

某人在山上种了N棵小树苗。冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定用3个L*L的正方形塑料薄膜将小树遮起来。我们不妨将山建立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个L*L的正方形的边要求平行与坐标轴,一个点如果在正方形的边界上,也算作被覆盖。当然,我们希望塑料薄膜面积越小越好,即求L最小值。

Input

第一行有一个正整数N,表示有多少棵树。接下来有N行,第i+1行有2个整数Xi,Yi,表示第i棵树的坐标,保证不会有2个树的坐标相同。

Output

一行,输出最小的L值。

Sample Input

4
0 1
0 -1
1 0
-1 0

Sample Output

1

HINT

首先可以确定此题满足可二分性,明显可以二分答案。所以我们只要能够在线性时间内检验即可了。

线性检测我们可以贪心解决,我们将每次还未被覆盖的点用一个最小的矩形来覆盖,然后每次选择用正方形覆盖它的四个角,总共递归三层,64种情况。所以我们枚举这64种情况,看是否能有一种能够覆盖所有的点。

这个贪心我开始没想到,现在也不会证明(理性想想是对的),我开始想的取左下角的点(x优先)为正方形左下角wa了,然后左下角的点(y优先)为正方形左下角wa了,再最左最下的两条平行坐标轴线的交点为正方形左下角还是wa了。最后将三者综合起来,还是wa了,但是正确率高了一些。这启发我以后贪心可以综合起来,取最优解正确率会高很多。

 1 #include<vector>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 using namespace std;
 7 
 8 #define inf (1<<29)
 9 #define maxn 20010
10 int n,x[maxn],y[maxn]; bool exist[maxn];
11 
12 inline bool dfs(int L,int step,int all)
13 {
14     if (all == n) return true;
15     if (step > 3) return false;
16     int up = -inf,down = inf,le = inf,ri = -inf;
17     for (int i = 1;i <= n;++i)
18         if (!exist[i])
19         {
20             up = max(y[i],up),down = min(y[i],down);
21             ri = max(x[i],ri),le = min(x[i],le);
22         }
23     int inc,nl,nr,nu,nd; vector <int> vec;
24     inc = 0; nl = le,nr = le+L,nu = up,nd = up-L;
25     for (int i = 1;i <= n;++i)
26         if (!exist[i] && x[i] >= nl&&x[i] <= nr&&y[i] >= nd&&y[i] <= nu)
27             ++inc,exist[i] = true,vec.push_back(i);
28     if (dfs(L,step+1,all+inc)) return true;
29     for (int i = 0;i < vec.size();++i) exist[vec[i]] = false; vec.clear();
30     inc = 0; nl = le,nr = le+L,nu = down+L,nd = down;
31     for (int i = 1;i <= n;++i)
32         if (!exist[i] && x[i] >= nl&&x[i] <= nr&&y[i] >= nd&&y[i] <= nu)
33             ++inc,exist[i] = true,vec.push_back(i);
34     if (dfs(L,step+1,all+inc)) return true;
35     for (int i = 0;i < vec.size();++i) exist[vec[i]] = false; vec.clear();
36     inc = 0; nl = ri-L,nr = ri,nu = up,nd = up-L;
37     for (int i = 1;i <= n;++i)
38         if (!exist[i] && x[i] >= nl&&x[i] <= nr&&y[i] >= nd&&y[i] <= nu)
39             ++inc,exist[i] = true,vec.push_back(i);
40     if (dfs(L,step+1,all+inc)) return true;
41     for (int i = 0;i < vec.size();++i) exist[vec[i]] = false; vec.clear();
42     inc = 0; nl = ri-L,nr = ri,nu = down+L,nd = down;
43     for (int i = 1;i <= n;++i)
44         if (!exist[i] && x[i] >= nl&&x[i] <= nr&&y[i] >= nd&&y[i] <= nu)
45             ++inc,exist[i] = true,vec.push_back(i);
46     if (dfs(L,step+1,all+inc)) return true;
47     for (int i = 0;i < vec.size();++i) exist[vec[i]] = false; vec.clear();
48     return false;
49 }
50 
51 inline bool okay(int L)
52 {
53     memset(exist,false,n+1);
54     return dfs(L,1,0);
55 }
56 
57 int main()
58 {
59     freopen("1052.in","r",stdin);
60     freopen("1052.out","w",stdout);
61     scanf("%d",&n); for (int i = 1;i <= n;++i) scanf("%d %d",&x[i],&y[i]);
62     if (okay(0)) printf("0"),exit(0);
63     int l = 1,r = inf,mid;
64     while (l <= r)
65     {
66         mid = (l + r) >> 1;
67         if (okay(mid)) r = mid - 1;
68         else l = mid + 1;
69     }
70     printf("%d",l);
71     fclose(stdin); fclose(stdout);
72     return 0;
73 }
View Code
原文地址:https://www.cnblogs.com/mmlz/p/4283635.html