http://www.lydsy.com/JudgeOnline/problem.php?id=1052
网格图,给出\(n\)个点,要求用3个边长相同的正方形覆盖所有点,求最小边长.
分析
显然是二分+判断可行性.
如何判断可行性呢?我们注意到是3个正方形.为什么是3个?
我们先找出覆盖所有点的最小距形,那么距形的四条边必须有正方形贴着,而又是3个正方形,所以至少要有1个正方形同时贴着两条边.
1.贴着的边相对
这样的话三个正方形都同时贴着相对的两条边,比如是上下两条边,那么贴着左边的那个正方形就贴着3条边,在距形的一角.
2.贴着的边相邻
这样的话这个正方形就在距形的一角.
所以我们递归的把正方形放在距形的一角,然后去掉已经覆盖了的点,继续放正方形即可.
1 #include <bits/stdc++.h> 2 #define fst first 3 #define scd second 4 using namespace std; 5 inline int read(int &x){x=0;int k=1;char c;for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';return x*=k;} 6 7 typedef pair <int,int> P; 8 const int maxn=20000+5,INF=0x7fffffff; 9 int n,ml,mr,mu,md; 10 P a[maxn]; 11 bool vis[maxn]; 12 bool dfs(int x,int t){ 13 if(t==3) return max(md-mu,mr-ml)<=x; 14 P b[4][2]; 15 b[0][0]=P(ml,mu),b[0][1]=P(ml+x,mu+x); 16 b[1][0]=P(ml,md-x),b[1][1]=P(ml+x,md); 17 b[2][0]=P(mr-x,mu),b[2][1]=P(mr,mu+x); 18 b[3][0]=P(mr-x,md-x),b[3][1]=P(mr,md); 19 for(int i=0;i<4;i++){ 20 int tl=ml,tr=mr,tu=mu,td=md; 21 int tmp[maxn]; 22 for(int j=1;j<=n;j++) tmp[j]=vis[j]; 23 for(int j=1;j<=n;j++) 24 if(a[j].fst>=b[i][0].fst&&a[j].fst<=b[i][1].fst&&a[j].scd>=b[i][0].scd&&a[j].scd<=b[i][1].scd) 25 vis[j]=true; 26 mu=ml=INF; mr=md=-INF; 27 for(int j=1;j<=n;j++)if(!vis[j]){ 28 mu=min(mu,a[j].scd); md=max(md,a[j].scd); 29 ml=min(ml,a[j].fst); mr=max(mr,a[j].fst); 30 } 31 bool flag=dfs(x,t+1); 32 ml=tl,mr=tr,mu=tu,md=td; 33 for(int j=1;j<=n;j++) vis[j]=tmp[j]; 34 if(flag) return true; 35 } 36 return false; 37 } 38 inline void solve(){ 39 int l=0,r=max(md-mu,mr-ml); 40 while(l<r){ 41 for(int i=1;i<=n;i++)if(vis[i]) puts("!"); 42 int mid=l+(r-l)/2; 43 if(dfs(mid,1)) r=mid; 44 else l=mid+1; 45 } 46 printf("%d\n",l); 47 } 48 inline void init(){ 49 read(n); 50 mu=ml=INF,mr=md=-INF; 51 for(int i=1;i<=n;i++){ 52 read(a[i].fst), read(a[i].scd); 53 ml=min(ml,a[i].fst); mr=max(mr,a[i].fst); 54 mu=min(mu,a[i].scd); md=max(md,a[i].scd); 55 } 56 } 57 int main(){ 58 init(); 59 solve(); 60 return 0; 61 }