1. 程式人生 > >BZOJ 1185 [HNOI2007]最小矩形覆蓋:凸包 + 旋轉卡殼

BZOJ 1185 [HNOI2007]最小矩形覆蓋:凸包 + 旋轉卡殼

read font return iostream operator 投影 class mod 平面

題目鏈接: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 }

BZOJ 1185 [HNOI2007]最小矩形覆蓋:凸包 + 旋轉卡殼