[BZOJ1185]最小矩形覆盖

上初三后遇到许多杂事,一度想放弃OI。

然后我就想着省赛随便浪,省赛之前沉迷于几乎不考的计算几何(因为写起来爽啊)

这个是写完模板后的第一题,看了之后感觉思路还挺清晰的。

首先因为它的tag是‘凸包‘,所以我们当然要先求凸包啦~Graham就好了

然后有一个结论是矩形的某一条边一定与凸包的某一条边共线,脑补一下如果不共线,稍微转一下矩形就会更小了。

那么我们枚举每一条凸包上的边x,每次找离x最远的点。

这里可以用二分,只有最远的那个点连接的两条边相对于x一个左转一个右转,把这条性质作为二分依据,就可以愉快地二分啦。

这题的细节处理较为烦人,像我这种弱智调了几天才调好。

代码如下

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<algorithm>
  4 using namespace std;
  5 #define dmax 1.7976931348623158e+308
  6 #define eps 1e-10
  7 struct point{
  8     double x,y,ang;
  9     int num;
 10 }a[100010],t;
 11 struct point2{
 12     double x,y;
 13     point2(){x=y=0;}
 14 }ha[100010];
 15 int n,i,ori,stack[100010];
 16 double miny,minx,orix,oriy,area;
 17 point2 p1,p2,p3,p4;
 18 double bigger(double x,double y){return x-y>=eps;}
 19 double notsm(double x,double y){return bigger(x,y)||abs(x-y)<=eps;}
 20 double angle(double x,double y){
 21     if(abs(x)<=eps)return dmax;
 22     return y/x;
 23 }
 24 bool cmp(point a,point b){
 25     if(bigger(b.ang,a.ang))return 1;
 26     if(bigger(a.ang,b.ang))return 0;
 27     return bigger(b.x*b.x+b.y*b.y,a.x*a.x+a.y*b.y);
 28 }
 29 double cross(double ax,double ay,double bx,double by){
 30     return ax*by-ay*bx;
 31 }
 32 int hassium(double vx,double vy,int ll,int rr){
 33     int l,r,m;
 34     l=ll+1;
 35     r=rr-1;
 36     while(l<=r){
 37         m=(l+r)/2;
 38         orix=cross(vx,vy,ha[m].x-ha[m-1].x,ha[m].y-ha[m-1].y);
 39         oriy=cross(vx,vy,ha[m+1].x-ha[m].x,ha[m+1].y-ha[m].y);
 40         if(orix>=eps){
 41             if(oriy>=eps)l=m+1;
 42             if(notsm(-oriy,0))return m;
 43         }
 44         if(abs(orix)<=eps)return m;
 45         if(orix<-eps)r=m-1;
 46     }
 47 }
 48 point2 getpoint(double xa,double ya,double x1,double y1,double xb,double yb,double x2,double y2){
 49     point2 p;
 50     if(abs(x1)<=eps){
 51         p.x=xa;
 52         p.y=yb;
 53         return p;
 54     }
 55     if(abs(y1)<=eps){
 56         p.x=xb;
 57         p.y=ya;
 58         return p;
 59     }
 60     p.y=((xb-xa)/x1/x2-yb/x1/y2+ya/x2/y1)/(1./x2/y1-1./x1/y2);
 61     p.x=(p.y-ya)/y1*x1+xa;
 62     return p;
 63 }
 64 double recta(double ax,double ay,double bx,double by){
 65     return sqrt((ax*ax+ay*ay)*(bx*bx+by*by));
 66 }
 67 void getrect(double vx,double vy,int num){
 68     int farest=hassium(vx,vy,num,num+stack[0]-1);
 69     int leftest=hassium(-vy,vx,farest,num+stack[0]-1),rightest=hassium(vy,-vx,num,farest);
 70     point2 t1=getpoint(ha[num].x-vx,ha[num].y-vy,vx,vy,ha[rightest].x,ha[rightest].y,vy,-vx),
 71            t2=getpoint(ha[rightest].x,ha[rightest].y,-vy,vx,ha[farest].x,ha[farest].y,vx,vy),
 72            t3=getpoint(ha[leftest].x,ha[leftest].y,-vy,vx,ha[farest].x,ha[farest].y,-vx,-vy),
 73            t4=getpoint(ha[leftest].x,ha[leftest].y,vy,-vx,ha[num].x,ha[num].y,-vx,-vy);
 74     double tarea=recta(t2.x-t1.x,t2.y-t1.y,t4.x-t1.x,t4.y-t1.y);
 75     if(bigger(area,tarea)){
 76         area=tarea;
 77         p1=t1;
 78         p2=t2;
 79         p3=t3;
 80         p4=t4;
 81     }
 82 }
 83 bool comp(point2 a,point2 b,point2 c,point2 d){
 84     return((bigger(b.y,a.y))||(abs(a.y-b.y)<=eps&&bigger(b.x,a.x)))
 85         &&((bigger(c.y,a.y))||(abs(a.y-c.y)<=eps&&bigger(c.x,a.x)))
 86         &&((bigger(d.y,a.y))||(abs(a.y-d.y)<=eps&&bigger(d.x,a.x)));
 87 }
 88 void gao(point2&a){
 89     if(a.x<0&&abs(a.x)<=1e-5)a.x=-a.x;
 90     if(a.y<0&&abs(a.y)<=1e-5)a.y=-a.y;
 91 }
 92 int main(){
 93     scanf("%d",&n);
 94     miny=minx=dmax;
 95     for(i=1;i<=n;i++){
 96         scanf("%lf%lf",&a[i].x,&a[i].y);
 97         a[i].num=i;
 98         if((a[i].x==minx&&a[i].y<miny)||a[i].x<minx){
 99             miny=a[i].y;
100             minx=a[i].x;
101             ori=i;
102         }
103     }
104     orix=a[ori].x;
105     oriy=a[ori].y;
106     for(i=1;i<=n;i++){
107         a[i].x-=orix;
108         a[i].y-=oriy;
109         if(i!=ori)
110          a[i].ang=angle(a[i].x,a[i].y);
111     }
112     t=a[1];
113     a[1]=a[ori];
114     a[ori]=t;
115     sort(a+2,a+n+1,cmp);
116     stack[0]=2;
117     stack[1]=1;
118     stack[2]=2;
119     for(i=3;i<=n;i++){
120         while(stack[0]>1&&cross(a[stack[stack[0]]].x-a[stack[stack[0]-1]].x,a[stack[stack[0]]].y-a[stack[stack[0]-1]].y,
121                                 a[i].x-a[stack[stack[0]]].x,a[i].y-a[stack[stack[0]]].y)<=0)stack[0]--;
122         stack[0]++;
123         stack[stack[0]]=i;
124     }
125     for(i=1;i<=n;i++){
126         a[i].x+=orix;
127         a[i].y+=oriy;
128     }
129     for(i=1;i<=stack[0];i++){
130         ha[i].x=a[stack[i]].x;
131         ha[i].y=a[stack[i]].y;
132     }
133     area=dmax;
134     getrect(ha[1].x-ha[stack[0]].x,ha[1].y-ha[stack[0]].y,1);
135     for(i=1;i<stack[0];i++){
136         ha[i+stack[0]]=ha[i];
137         getrect(ha[i+1].x-ha[i].x,ha[i+1].y-ha[i].y,i+1);
138     }
139     gao(p1);
140     gao(p2);
141     gao(p3);
142     gao(p4);
143     printf("%.5lf\n",area);
144     if(comp(p1,p2,p3,p4))
145      printf("%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n",p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,p4.x,p4.y);
146     if(comp(p2,p1,p3,p4))
147      printf("%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n",p2.x,p2.y,p3.x,p3.y,p4.x,p4.y,p1.x,p1.y);
148     if(comp(p3,p2,p1,p4))
149      printf("%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n",p3.x,p3.y,p4.x,p4.y,p1.x,p1.y,p2.x,p2.y);
150     if(comp(p4,p2,p3,p1))
151      printf("%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n%.5lf %.5lf\n",p4.x,p4.y,p1.x,p1.y,p2.x,p2.y,p3.x,p3.y);
152 }
时间: 2024-12-18 18:10:20

[BZOJ1185]最小矩形覆盖的相关文章

bzoj1185【HNOI2007】最小矩形覆盖

1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 1114  Solved: 505 [Submit][Status][Discuss] Description 凸包+旋转卡壳 首先有一个结论:矩形一定有一条边在凸包上,否则我们旋转之后一定会得到一个更小的矩形,脑补一下. 然后枚举凸包上的边,用旋转卡壳维护矩形的另外三条边,同时更新答案即可. #include<ios

bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包

[HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 2081  Solved: 920[Submit][Status][Discuss] Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, 输出所求矩形的面积和四个顶点坐标 Input 第一行为一个整数n(3<=n<=50000) 从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计

1185: [HNOI2007]最小矩形覆盖

1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1426  Solved: 648[Submit][Status][Discuss] Description Input Output Sample Input Sample Output HINT Source 计算几何 vfleaking提供Spj #include<cstdio> #include<cmat

【bzoj_1185】[HNOI2007]最小矩形覆盖

咳咳..这会来总结一下1185的解题思路(这么一道破题调了一整天我会乱说? 首先做凸包,这个谁都知道我就不说了 然后问题转化为了凸多边形的最小矩形覆盖 有一个结论是 一个凸包的最小矩形覆盖一定有矩形的一条边在凸包上 请注意是结论..不是猜想.这个结论的正确性嘛..wys神犇给出的解释是这样的 好吧.. 然后我们可以以逆时针的顺序枚举每条边,作为矩形的一条边所在的直线.显然,矩形与这条边平行的边一定过这条边的对踵点.这一步骤旋转卡壳就可以在均摊O(1)的时间下完成. 然后问题来了,如何在快速找到最

bzoj 1185 旋转卡壳 最小矩形覆盖

题目大意 就是求一个最小矩形覆盖,逆时针输出其上面的点 这里可以看出,那个最小的矩形覆盖必然有一条边经过其中凸包上的两个点,另外三条边必然至少经过其中一个点,而这样的每一个点逆时针走一遍都满足单调性 所以可以利用旋转卡壳的思想找到这样的三个点 以每一条边作为基础,循环n次得到n个这样的矩形,找到其中面积最小的即可 然后自己画画图,作出矩形对应的两条边的单位向量,那么这四个点就非常好求了 1 #include <iostream> 2 #include <cstdio> 3 #inc

BZOJ 1185 HNOI2007 最小矩形覆盖 旋转卡壳

题目大意:最小矩形覆盖 首先有一个结论:凸包上一定有一条边与矩形的一条边重合 证明:如果不存在一条边与矩形的一条边重合,那么我将这个矩形旋转一下一定会比之前更小 于是我们枚举其中一条边,对其余三个点卡壳即可 这旋转卡壳写的真叫一个卡壳- - 还好1A掉了- - #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

BZOJ1185: [HNOI2007]最小矩形覆盖

传送门 旋转卡壳. 首先求凸包没什么好商量的. 然后有一个结论,如果存在一个最小的矩形覆盖,那么凸包里必定存在一条边和矩形的边重合. 自己yy一下就好啦,很容易想明白. 然后枚举每条边,移动另外三条边即可. 注意点积,叉积的结合运用什么的. //BZOJ 1185 //by Cydiater //2017.1.29 #include <iostream> #include <map> #include <ctime> #include <cmath> #in

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])上投影长度的单调性求出. 最后将

【模板】【计几】最小矩形覆盖(bzoj1185)

参考hzwer的:http://hzwer.com/5805.html 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185 题意:给你n个点,求面积最小的矩形使得它覆盖这n个点 矩形一条边是在凸包上的,所以枚举凸包上的边,并且旋转卡壳维护以这条边为底边的最左点,最右点,最上点,然后就可以找到这个矩形了,复杂度O(n) 1 /******************************************************