题目链接:http://poj.org/problem?id=2187
题意:求出给定点集的最远点对距离
首先知道一点,最远点对一定是在这些点集构成的凸包的边上,所以可以先求出凸包,再枚举凸包上所有点对即可,用nlogn的时间求凸包,然后用k^2的时间求最远点对,另外还有一种较快方法可以求凸包上的最远点对,旋转卡壳法,就是找出可以刚好卡着凸包的两条平行线,然后对旋转,可以知道,最远点对一定在分这两条平行线上,旋转过程中求出最远的即可。
不过就此题而言,用旋转卡壳和枚举在时间上并没有多大的差别,只能说点集很大,而在凸包上的点很小,或者,RC写的有问题?
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #define M 50008 const double eps = 1e-8; typedef struct{ double x,y; }Point; Point pt[M]; int stk[M]; int top; double Multi(Point p,Point q,Point o) { return (p.x-o.x)*(q.y-o.y)-(q.x-o.x)*(p.y-o.y); } double Dis(Point p,Point q) { return (p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y); } int Cmp(const void *a,const void *b) { Point *p=(Point *)a; Point *q=(Point *)b; double d=Multi(*p,*q,pt[0]); if(fabs(d)<eps) return Dis(*p,pt[0])>Dis(*q,pt[0])?1:-1; return d<0?1:-1; } double RC() { int i,p; double ans=0,a1,a2; stk[top]=stk[0];//stk[top+1]=stk[1]; for(i=0,p=1;i<top;i++){//对每条边,找距其最远的点,然后旋转 while(Multi(pt[stk[i]],pt[stk[i+1]],pt[stk[p]]) <Multi(pt[stk[i]],pt[stk[i+1]],pt[stk[p+1]])) p++,p%=top; //有可能平行 a1=Dis(pt[stk[i]],pt[stk[p]]); a2=Dis(pt[stk[i+1]],pt[stk[p+1]]); if(a1>ans) ans=a1; if(a2>ans) ans=a2; } return ans; } int main() { int n,i,k; Point tmp; double ans,d; while(~scanf("%d",&n)){ for(k=i=0;i<n;i++){ scanf("%lf%lf",&pt[i].x,&pt[i].y); if(pt[i].y<pt[k].y||fabs(pt[i].y-pt[k].y)<eps&&pt[i].x<pt[k].x) k=i; } tmp=pt[0],pt[0]=pt[k],pt[k]=tmp; qsort(pt,n,sizeof(pt[0]),Cmp); for(i=0;i<2;i++) stk[top++]=i; for(i=2;i<n;i++){ while(top>1&&Multi(pt[stk[top-2]],pt[stk[top-1]],pt[i])<=0) top--;//RC,要去掉在同一条边上的中间的点 stk[top++]=i; } /*ans=0; for(i=0;i<top;i++){ for(j=i+1;j<top;j++){ d=Dis(pt[stk[i]],pt[stk[j]]); if(d>ans) ans=d; } }*/ printf("%.0f/n",RC()); } return 0; }