BZOJ 1185 [HNOI2007]最小矩形覆盖:凸包 + 旋转卡壳
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185
题意:
给出二维平面上的n个点,问你将所有点覆盖的最小矩形面积。
题解:
先找出凸包,然后旋转卡壳。
在旋转卡壳中有一个结论:最小覆盖矩形一定有一条边在凸包上。
所以先枚举矩形在凸包上的那条边(p[i],p[i+1]),然后利用单调性找出p[i]的对踵点p[u]。
至于左右两侧的切点p[l]和p[r],要利用它们连线在直线(p[i],p[i+1])上投影长度的单调性求出。
最后将找出的矩形顶点再做一遍极角排序即可。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #include <algorithm> 6 #define MAX_N 50005 7 #define INF_LF 1e14 8 #define EPS 1e-7 9 10 using namespace std; 11 12 struct Coor 13 { 14 double x,y; 15 Coor(double _x,double _y) { x=_x,y=_y; } 16 Coor(){} 17 friend Coor operator + (const Coor &a,const Coor &b) 18 { 19 return Coor(a.x+b.x,a.y+b.y); 20 } 21 friend Coor operator - (const Coor &a,const Coor &b) 22 { 23 return Coor(a.x-b.x,a.y-b.y); 24 } 25 friend Coor operator * (const Coor &a,double b) 26 { 27 return Coor(a.x*b,a.y*b); 28 } 29 friend Coor operator / (const Coor &a,double b) 30 { 31 return Coor(a.x/b,a.y/b); 32 } 33 friend double len(const Coor &a,const Coor &b) 34 { 35 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 36 } 37 friend double dot(const Coor &a,const Coor &b) 38 { 39 return a.x*b.x+a.y*b.y; 40 } 41 friend double cross(const Coor &a,const Coor &b) 42 { 43 return a.x*b.y-a.y*b.x; 44 } 45 friend double area(const Coor &a,const Coor &b,const Coor &c) 46 { 47 return fabs(cross(b-a,c-a)); 48 } 49 friend double length(const Coor &a) 50 { 51 return sqrt(dot(a,a)); 52 } 53 friend double pro(const Coor &a,const Coor &b) 54 { 55 return dot(a,b)/length(b); 56 } 57 friend Coor proc(const Coor &a,const Coor &b,const Coor &c) 58 { 59 Coor v=c-b; 60 return b+v*dot(v,a-b)/dot(v,v); 61 } 62 }; 63 64 int n,tot=0; 65 double ans=INF_LF; 66 Coor p[MAX_N]; 67 Coor con[MAX_N]; 68 Coor rect[MAX_N]; 69 70 void read() 71 { 72 scanf("%d",&n); 73 for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 74 } 75 76 bool cmp(const Coor &a,const Coor &b) 77 { 78 double c=cross(a-p[1],b-p[1]); 79 return c!=0 ? c>0 : len(p[1],a)<len(p[1],b); 80 } 81 82 inline bool eq(double x,double y) 83 { 84 return fabs(x-y)<EPS; 85 } 86 87 void graham() 88 { 89 for(int i=2;i<=n;i++) 90 { 91 if(p[i].y<p[1].y || (p[i].y==p[1].y && p[i].x<p[1].x)) 92 { 93 swap(p[i],p[1]); 94 } 95 } 96 sort(p+2,p+1+n,cmp); 97 con[++tot]=p[1],con[++tot]=p[2]; 98 for(int i=3;i<=n;i++) 99 { 100 while(tot>=2 && cross(con[tot]-con[tot-1],p[i]-con[tot])<=0) tot--; 101 con[++tot]=p[i]; 102 } 103 } 104 105 inline int mod(int x) 106 { 107 return ((x-1)%tot+tot)%tot+1; 108 } 109 110 void rc() 111 { 112 int u=2,l=1,r=1; 113 for(int i=2;i<=tot;i++) 114 { 115 if(con[i].x<con[l].x || (con[i].x==con[l].x && con[i].y>con[l].y)) l=i; 116 if(con[i].x>con[r].x || (con[i].x==con[r].x && con[i].y<con[r].y)) r=i; 117 } 118 for(int i=1;i<=tot;i++) 119 { 120 while(area(con[i],con[mod(i+1)],con[u])<area(con[i],con[mod(i+1)],con[mod(u+1)])) u=mod(u+1); 121 while(pro(con[r]-con[l],con[mod(i+1)]-con[i])<pro(con[r]-con[mod(l+1)],con[mod(i+1)]-con[i])) l=mod(l+1); 122 while(pro(con[r]-con[l],con[mod(i+1)]-con[i])<pro(con[mod(r+1)]-con[l],con[mod(i+1)]-con[i])) r=mod(r+1); 123 double w=pro(con[r]-con[l],con[mod(i+1)]-con[i]); 124 double h=area(con[i],con[mod(i+1)],con[u])/length(con[mod(i+1)]-con[i]); 125 if(w*h<ans) 126 { 127 ans=w*h; 128 Coor v=con[mod(i+1)]-con[i]; 129 rect[0]=proc(con[l],con[i],con[mod(i+1)]); 130 rect[1]=proc(con[r],con[i],con[mod(i+1)]); 131 rect[2]=proc(con[l],con[u],con[u]+v); 132 rect[3]=proc(con[r],con[u],con[u]+v); 133 } 134 } 135 for(int i=1;i<4;i++) 136 { 137 if(rect[i].y<rect[0].y || (rect[i].y==rect[0].y && rect[i].x<rect[0].x)) 138 { 139 swap(rect[0],rect[i]); 140 } 141 } 142 sort(rect+1,rect+4,cmp); 143 for(int i=0;i<4;i++) 144 { 145 if(eq(rect[i].x,0)) rect[i].x=0; 146 if(eq(rect[i].y,0)) rect[i].y=0; 147 } 148 } 149 150 void work() 151 { 152 graham(); 153 rc(); 154 printf("%.5f\n",ans); 155 for(int i=0;i<4;i++) printf("%.5f %.5f\n",rect[i].x,rect[i].y); 156 } 157 158 int main() 159 { 160 read(); 161 work(); 162 }