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

[ 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值