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

Leohh發表於2018-04-28

題目連結: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 }

 

相關文章