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

参考hzwer的:http://hzwer.com/5805.html

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185

题意:给你n个点,求面积最小的矩形使得它覆盖这n个点

矩形一条边是在凸包上的,所以枚举凸包上的边,并且旋转卡壳维护以这条边为底边的最左点,最右点,最上点,然后就可以找到这个矩形了,复杂度O(n)

 1 /**************************************************************
 2     Problem: 1185
 3     User: xiaobuxie
 4     Language: C++
 5     Result: Accepted
 6     Time:232 ms
 7     Memory:2860 kb
 8 ****************************************************************/
 9
10 #include<iostream>
11 #include<cstdio>
12 #include<algorithm>
13 #include<cmath>
14 using namespace std;
15 const int N = 5e4+9;
16 #define eps 1e-7
17 struct Point{
18     double x,y;
19     Point operator - (Point b){
20         return (Point){ x - b.x,y - b.y};
21     }
22     Point operator + (Point b){
23         return (Point){x+b.x,y+b.y};
24     }
25     Point operator * (double v ){
26         return (Point){ v * x,v * y};
27     }
28 }p[N],ch[N],ansp[10],temp[10];
29 double ans;
30 double cross(Point a,Point b,Point c){
31     return ( b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
32 }
33 double dot( Point a,Point b,Point c){
34     return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
35 }
36 double dis(Point a,Point b){
37     return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
38 }
39 bool cmp(Point a,Point b){
40     if( fabs(a.x - b.x) < eps ) return a.y < b.y - eps;
41     return a.x < b.x ;
42 }
43 int n,m;
44 void Andrew(){
45     sort(p,p+n,cmp);
46     m = 0;
47     for(int i = 0;i<n;++i){
48         while( m > 1 && cross( ch[m-2] , p[i],ch[m-1]) > -eps) --m;
49         ch[m++] = p[i];
50     }
51     int k = m;
52     for(int i = n-2;i>=0;--i){
53         while( m > k && cross(ch[m-2],p[i],ch[m-1]) > -eps) --m;
54         ch[m++] = p[i];
55     }
56     if( n > 1) --m;
57 }
58 void RC(){
59     int l = 1,r = 1,h = 1;
60     ans = 1e60;
61     double L,R,D,H;
62     ch[m] = ch[0];
63     for(int i = 0;i<m;++i){
64         D = dis(ch[i],ch[i+1]);
65         while( cross(ch[i],ch[i+1],ch[h+1]) - cross(ch[i],ch[i+1],ch[h]) > -eps) h = (h+1) % m;
66         while( dot(ch[i],ch[i+1],ch[r+1]) - dot(ch[i],ch[i+1],ch[r]) > -eps) r = (r+1) % m;
67         if( i == 0 ) l = r;
68         while( dot(ch[i],ch[i+1],ch[l+1]) - dot(ch[i],ch[i+1],ch[l]) < eps) l = (l+1) % m;
69         L = dot(ch[i],ch[i+1],ch[l]) / D;
70         R = dot(ch[i],ch[i+1],ch[r]) / D;
71         H = cross(ch[i],ch[i+1],ch[h]) / D;
72         if( H < 0 ) H = -H;
73         double S = (R-L) * H;
74         if( S < ans - eps){
75             ans = S;
76             ansp[0] = ch[i] + (ch[i+1] - ch[i]) * (R/D);
77             ansp[1] = ansp[0] + (ch[r] - ansp[0]) * ( H / dis(ansp[0],ch[r]) );
78             ansp[2] = ansp[1] - (ansp[0] - ch[i]) * ( (R-L) / dis(ansp[0],ch[i]));
79             ansp[3] = ansp[2] - ( ansp[1] - ansp[0] );
80         }
81     }
82 }
83 int main(){
84     scanf("%d",&n);
85     for(int i = 0;i<n;++i) scanf("%lf %lf",&p[i].x,&p[i].y);
86     Andrew();
87     RC();
88     printf("%.5f\n",ans);
89     int id = 0;
90     for(int i = 1;i<=3;++i){
91         if( ansp[i].y < ansp[id].y - eps || ( fabs(ansp[i].y - ansp[id].y)<eps && ansp[i].x < ansp[id].x - eps )){
92             id = i;
93         }
94     }
95     for(int i = 0;i<=3;++i){
96         printf("%.5f %.5f\n",ansp[ (i+id) % 4].x,ansp[ (i + id)%4].y);
97     }
98     return 0;
99 }

原文地址:https://www.cnblogs.com/xiaobuxie/p/12260631.html

时间: 2024-12-18 18:10:22

【模板】【计几】最小矩形覆盖(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]最小矩形覆盖

上初三后遇到许多杂事,一度想放弃OI. 然后我就想着省赛随便浪,省赛之前沉迷于几乎不考的计算几何(因为写起来爽啊) 这个是写完模板后的第一题,看了之后感觉思路还挺清晰的. 首先因为它的tag是'凸包',所以我们当然要先求凸包啦~Graham就好了 然后有一个结论是矩形的某一条边一定与凸包的某一条边共线,脑补一下如果不共线,稍微转一下矩形就会更小了. 那么我们枚举每一条凸包上的边x,每次找离x最远的点. 这里可以用二分,只有最远的那个点连接的两条边相对于x一个左转一个右转,把这条性质作为二分依据,