As Jacques-Édouard really likes birthday cakes, he celebrateshis birthday every hour, instead of every year. His friendsordered him a round cake from a famous pastry shop, andplaced candles on its top surface. The number of candlesequals the age of Jacques-Édouard in hours. As a result,there is a huge amount of candles burning on the top of thecake. Jacques-Édouard wants to blow all the candles out inone single breath.You can think of the flames of the candles as being pointsin the same plane, all within a disk of radius R (in nanometers)centered at the origin. On that same plane, the airblown by Jacques-Édouard follows a trajectory that can bedescribed by a straight strip of width W, which comprisesthe area between two parallel lines at distance W, the linesthemselves being included in that area. What is the minimum width W such that Jacques-Édouardcan blow all the candles out if he chooses the best orientation to blow?
Input
The input file contains several test cases, each of them as described below.The first line consists of the integers N and R, separated with a space, where N is Jacques-Édouard’sage in hours. Then N lines follow, each of them consisting of the two integer coordinates xi and yi ofthe i-th candle in nanometers, separated with a space.
Limits
• 3 ≤ N ≤ 2 · 105;
• 10 ≤ R ≤ 2 · 108;
• for 1 ≤ i ≤ N, x2i + y2i ≤ R2;
• all points have distinct coordinates.
Output
For each test case, the output must follow the description below.Print the value W as a floating point number. An additive or multiplicative error of 10−5is tolerated:if y is the answer, any number either within [y − 10−5; y + 10−5] or within [(1 − 10−5)y; (1 + 10−5)y] isaccepted.Sample Input3 100 010 00 10Sample Output7.0710678118654755
题意:在半径为R的范围内有一些点,求能把他们包围住的矩形的最窄宽度。
思路:求凸包,再利用旋转卡壳,求出凸多边形的宽。先取凸包上一条边,在取一个点,直到这个点离这条边最远,然后顺时针枚举凸包上的边,这个点也会顺时针变化,这个操作复杂度为O(n)。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
//平面点的结构体模板
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){ x=_x; y=_y; }
Point operator + (Point p){ return Point(x+p.x,y+p.y); }
Point operator - (Point p){ return Point(x-p.x,y-p.y); }
Point operator * (double d){ return Point(d*x,d*y); }
double dot(Point p){ return x*p.x+y*p.y; } //内积
//外积,外积等于0则两点连线过原点或矢量平行,>0则连线斜率>45°,<0则连线斜率<45°
double det(Point p){ return x*p.y-p.x*y; }
}ps[200010];
//加上操作变成凸包模板
int n;
bool cmpxy(const Point &p,const Point &q){ //排序
if(p.x!=q.x) return p.x<q.x;
return p.y<q.y;
}
vector<Point> convex_hull(Point *ps,int n){
sort(ps,ps+n,cmpxy);
int k=0;
vector<Point> qs(n*2); //构造中的凸包
for(int i=0;i<n;++i){ //构造凸包的下侧
//相邻边的叉积大于0
while(k>1 && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0)--k;
qs[k++]=ps[i];
}
for(int i=n-2,t=k;i>=0;--i){ //构造凸包的上侧
//相邻边的叉积小于0
while(k>t && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0)--k;
qs[k++]=ps[i];
}
qs.resize(k-1); //去掉重复的左下角点
return qs;
}
double dist(Point p,Point q){ //两点距离平方
return (p-q).dot(p-q);
}
int main()
{
int n,r;
while(~scanf("%d%d",&n,&r)&&n)
{
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&ps[i].x,&ps[i].y);
}
vector<Point> qs=convex_hull(ps,n);
int p=1;
double len;
int sz=qs.size();
if(sz==2)
{
printf("0.000000000\n");
continue;
}
double minofmaxh=2.0*r;
qs[sz]=qs[0];
for(int i=0;i<sz;i++)
{
len=sqrt(dist(qs[i],qs[i+1]));
while(true)
{
double h=fabs((qs[i]-qs[i+1]).det(qs[p]-qs[i+1]))/len;
if(p<sz-1)
{
double h1=fabs((qs[i]-qs[i+1]).det(qs[p+1]-qs[i+1]))/len;
if(h1>=h)
{
p++;
}
else
{
minofmaxh=min(minofmaxh,h);
break;
}
}
else
{
double h1=fabs((qs[i]-qs[i+1]).det(qs[0]-qs[i+1]))/len;
if(h1>=h)
{
p=0;
}
else
{
minofmaxh=min(minofmaxh,h);
break;
}
}
}
}
printf("%.10lf\n",minofmaxh);
}
}