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

[HNOI2007]最小矩形覆盖

Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
Submit: 2081  Solved: 920
[Submit][Status][Discuss]

Description

给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,

输出所求矩形的面积和四个顶点坐标

Input

第一行为一个整数n(3<=n<=50000)

从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计数法

Output

第一行为一个浮点数,表示所求矩形的面积(精确到小数点后5位),

接下来4行每行表示一个顶点坐标,要求第一行为y坐标最小的顶点,

其后按逆时针输出顶点坐标.如果用相同y坐标,先输出最小x坐标的顶点

Sample Input

6 1.0 3.00000
1 4.00000
2.0000 1
3 0.0000
3.00000 6
6.0 3.0

Sample Output

18.00000
3.00000 0.00000
6.00000 3.00000
3.00000 6.00000
0.00000 3.00000

HINT

Source

vfleaking提供Spj

[Submit][Status][Discuss]

HOME Back

首先有一个结论,矩形的一条边一定在凸包上!!!

枚举凸包上的边

用旋转卡壳在凸包上找矩形另外三点。。

差不多吧,其它三个点可以找的吧,而且也是有单调性的。

 1 #pragma GCC optimize(2)
 2 #pragma G++ optimize(2)
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cstdio>
 8
 9 #define eps 0.00000001
10 #define N 50007
11 using namespace std;
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
16     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
17     return x*f;
18 }
19
20 int n,tot;
21 double ans=1e60;
22 struct P
23 {
24     double x,y;
25     P(){}
26     P(double _x,double _y):x(_x),y(_y){}
27     friend bool operator<(P a,P b){return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;}
28     friend bool operator==(P a,P b){return fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps;}
29     friend bool operator!=(P a,P b){return !(a==b);}
30     friend P operator+(P a,P b){return P(a.x+b.x,a.y+b.y);}
31     friend P operator-(P a,P b){return P(a.x-b.x,a.y-b.y);}
32     friend double operator*(P a,P b){return a.x*b.y-a.y*b.x;}
33     friend P operator*(P a,double b){return P(a.x*b,a.y*b);}
34     friend double operator/(P a,P b){return a.x*b.x+a.y*b.y;}
35     friend double dis(P a){return sqrt(a.x*a.x+a.y*a.y);}
36 }p[N],q[N],t[5];
37
38 bool cmp(P a,P b)
39 {
40     double t=(a-p[1])*(b-p[1]);
41     if(fabs(t)<eps)return dis(p[1]-a)-dis(p[1]-b)<0;
42     return t>0;
43 }
44 void Graham()
45 {
46     for (int i=2;i<=n;i++)
47         if(p[i]<p[1])swap(p[i],p[1]);
48     sort(p+2,p+n+1,cmp);
49     q[++tot]=p[1];
50     for (int i=2;i<=n;i++)
51     {
52         while(tot>1&&(q[tot]-q[tot-1])*(p[i]-q[tot])<eps)tot--;
53         q[++tot]=p[i];
54     }
55     q[0]=q[tot];//凸包是一个回路。
56 }
57 void RC()
58 {
59     int l=1,r=1,p=1;
60     double L,R,D,H;
61     for (int i=0;i<tot;i++)
62     {
63         D=dis(q[i]-q[i+1]);
64         while((q[i+1]-q[i])*(q[p+1]-q[i])-(q[i+1]-q[i])*(q[p]-q[i])>-eps)p=(p+1)%tot;
65         while((q[i+1]-q[i])/(q[r+1]-q[i])-(q[i+1]-q[i])/(q[r]-q[i])>-eps)r=(r+1)%tot;
66         if(i==0)l=r;
67         while((q[i+1]-q[i])/(q[l+1]-q[i])-(q[i+1]-q[i])/(q[l]-q[i])<eps)l=(l+1)%tot;
68         L=(q[i+1]-q[i])/(q[l]-q[i])/D,R=(q[i+1]-q[i])/(q[r]-q[i])/D;
69         H=(q[i+1]-q[i])*(q[p]-q[i])/D;
70         if(H<0)H=-H;
71         double tmp=(R-L)*H;
72         if(tmp<ans)
73         {
74             ans=tmp;
75             t[0]=q[i]+(q[i+1]-q[i])*(R/D);
76             t[1]=t[0]+(q[r]-t[0])*(H/dis(t[0]-q[r]));
77             t[2]=t[1]-(t[0]-q[i])*((R-L)/dis(q[i]-t[0]));
78             t[3]=t[2]-(t[1]-t[0]);
79         }
80     }
81 }
82 int main()
83 {
84     n=read();
85     for (int i=1;i<=n;i++)
86         scanf("%lf%lf",&p[i].x,&p[i].y);
87     Graham();
88     RC();
89     printf("%.5lf\n",ans);
90     int fir=0;
91     for (int i=1;i<=3;i++)
92         if(t[i]<t[fir])fir=i;
93     for (int i=0;i<=3;i++)
94         printf("%.5lf %.5lf\n",t[(i+fir)%4].x,t[(i+fir)%4].y);
95 }

原文地址:https://www.cnblogs.com/fengzhiyuan/p/8530629.html

时间: 2024-12-08 11:42:22

bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包的相关文章

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

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

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

题目大意:给出平面上的一些点,问面积最小的矩形满足覆盖所有的点. 思路:覆盖问题和不是凸包上的点没关系,先做凸包.根据贪心的思想,这个覆盖了所有点的矩形肯定至少有一条边与凸包上的边重合,那么我们枚举凸包上的每一条边,对于这个已经确定了一条边的矩形,不难确定其他三个边.注意到已知当前直线的向量,就可以求出两侧和对面的向量,而这三个向量随着枚举的边的移动是单调的,所以就可以用旋转卡壳来卡住剩下的三条边. 但是旋转卡壳时的初值会出问题,如果按照逆时针的顺序求出剩下的三条边的时候,要想通过向量直接卡第三

BZOJ1185: [HNOI2007]最小矩形覆盖

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

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

Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离

\(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接这两个岛屿.为了把成本降到最低,国王要求你,主教,找到两个岛屿边界之间最小的距离. \(\color{#0066ff}{输入格式}\) 输入由几个测试用例组成. 每个测试用两个整数n,m(3≤n,m≤10000)开始 接下来的n行中的每一行都包含一对坐标,用来描述顶点在一个凸多边形中的位置. 下一条

bzoj1185【HNOI2007】最小矩形覆盖

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

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

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