题意:给出含n(1<n<50000)个点的点集,求两点间的最大距离;
思路:旋转卡壳求最大距离,用两平行线将凸包夹住,凸包在平行线间旋转,记录最大距离;
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const double epsi=1e-10; const double pi=acos(-1.0); const int maxn=50005; struct point{ double x,y; point(){} point(double xx,double yy):x(xx),y(yy){} point operator -(const point &op2)const{ return point(x-op2.x,y-op2.y); } point operator +(const point &op2)const{ return point(x+op2.x,y+op2.y); } double operator *(const point &op2)const{ return x*op2.x+y*op2.y; } double operator ^(const point &op2) const{ //两个点向量的叉积 return x*op2.y-y*op2.x; } }; inline int sign(const double &x){ if(x>epsi) return 1; if(x<-epsi) return -1; return 0; } inline double sqr(const double &x){ return x*x; } inline double mul(const point &p0,const point &p1,const point &p2){ return (p1-p0)^(p2-p0); } inline double dis2(const point &p0,const point &p1){ return sqr(p0.x-p1.x)+sqr(p0.y-p1.y); } inline double dis(const point &p0,const point &p1){ return sqrt(dis2(p0,p1)); } inline double dis(const point &p0,const point &p1,const point &p2) //p0与直线p1p2的距离 { return fabs(mul(p0,p1,p2)/dis(p1,p2)); } inline point rotate(const point &p,const double &ang){ //p旋转ang角度 return point(p.x*cos(ang)-p.y*sin(ang),p.x*sin(ang)+p.y*cos(ang)); } inline double calang(const point &p0,const point &p1,const point &p2) //计算p0p1与p0p2间的夹角 { return acos((p1-p0)*(p2-p0)/dis(p0,p1)/dis(p0,p2)); } int n,l; //n个顶点,最近距离为l point p[maxn],tp[maxn],convex_hull; //多边形顶点序列为p[],最低位置的点为convex_hull inline bool cmp(const point &a,const point &b){ //相对最低点,各点极角从小到大,距离从近到远排序 return sign(mul(convex_hull,a,b))>0||sign(mul(convex_hull,a,b))==0&&dis2(convex_hull,a)<dis2(convex_hull,b); } int convex(point *a,int n,point *b){ //计算含n个点的点集a的凸包b //if(n<3) printf("Wrong in Line %d ",__LINE__); //顶点数小于3,输出失败信息 for(int i=1;i<n;i++) //计算最低点convex_hull if(sign(a[i].x-a[0].x)<0||sign(a[i].x-a[0].x)==0&&sign(a[i].y-a[0].y)<0) swap(a[0],a[i]); convex_hull=a[0]; sort(a,a+n,cmp); //按极角和距离排序 int newn=2; b[0]=a[0];b[1]=a[1]; //a[0],a[1]入栈 for(int i=2;i<n;i++){ while(newn>1&&sign(mul(b[newn-1],b[newn-2],a[i]))>=0) --newn; //弹出栈顶所有未左转指向扫描顶点i的元素 b[newn++]=a[i]; //顶点i入栈 } return newn; //栈顶指针 } double rotating(point *p,const int &n){ //在含n个顶点的凸包中计算最远距离 // if(n<2) printf("Wrong in line %d ",__LINE__); int u[4]; point v[4]; u[0]=u[1]=u[2]=u[3]=0; //最低点、最右点、最高点、最左点 v[0]=point(1,0),v[1]=point(0,1),v[2]=point(-1,0),v[3]=point(0,-1); //4个端点的位移向量,其中最低点右移、最右点上移、最高点左移、最左点下移 p[n]=p[0]; for(int i=1;i<n;i++){ if(sign(p[i].y-p[u[0]].y)<0||sign(p[i].y-p[u[0]].y)==0&&sign(p[i].x-p[u[0]].x)>0) u[0]=i;//计算最低点 if(sign(p[i].x-p[u[1]].x)>0||sign(p[i].x-p[u[1]].x)==0&&sign(p[i].y-p[u[1]].y)>0) u[1]=i;//计算最右点 if(sign(p[i].y-p[u[2]].y)>0||sign(p[i].y-p[u[2]].y)==0&&sign(p[i].x-p[u[2]].x)<0) u[2]=i;//计算最高点 if(sign(p[i].y-p[u[3]].y)<0||sign(p[i].y-p[u[3]].y)==0&&sign(p[i].x-p[u[3]].x)<0) u[3]=i;//计算最左点 } double ret=dis(p[u[0]],p[u[2]]); //最远距离初始化为最低点与最高点间的距离 double sumang=0,curang,ang[4]; //总旋转角度、当前旋转角度 while(sign(sumang-2*pi)<=0){ curang=1e30; //初始化当前旋转角度 for(int i=0;i<4;i++)//枚举四个端点,计算i方向位移后的位置与下一个顶点相对端点的夹角ang[i],最小夹角curang作为平行线的旋转角度 curang=min(curang,ang[i]=calang(p[u[i]],p[u[i]]+v[i],p[u[i]+1])); for(int i=0;i<4;i++){ v[i]=rotate(v[i],curang);//向量旋转curang度 if(sign(curang-ang[i])==0) u[i]=(u[i]+1)%n;//旋转curang度的顶点逆时针取下一个顶点作为端点 } sumang+=curang;//累计旋转总角度 ret=max(ret,dis(p[u[0]],p[u[2]]));//用当前最高点与最低点的距离调整最大距离 } return ret; } int main(){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); n=convex(p,n,tp); // p[n]=p[0]; //首尾相连 double ans=rotating(tp,n); printf("%d ",(int)sqr(ans)); return 0; }