http://poj.org/problem?id=2187
题意:给平面上一个点集,求最远两个点的距离平方
显然这个最远的点对是在凸包上的,先求出凸包
本题n=5e4
而凸包的求法有几种,如卷包裹法(复杂度nh,不太合适)
或grahamscan算法(nlogn)要注意的是本题中实现是求到 凸包的顶点集,没有包括凸包边上的非端点。。。
然后本题直接暴力枚举凸包顶点求最远点对也是OK,,,第一次跑了800ms。第二次跑300ms了。。。
数据比较bt的时候可以用旋转卡壳(xuan zhuan qia ke)
O(n)的复杂度找到最远点对
grahamscan算法求凸包+旋转卡壳:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=1e-5; double max(double a,double b) {return a>b?a:b;} double min(double a,double b) {return a<b?a:b;} struct POINT { double x; double y; POINT(double a=0, double b=0) { x=a; y=b;} //constructor }; struct LINESEG { POINT s; POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} LINESEG() { } }; struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0 { double a; double b; double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} }; double multiply(POINT sp,POINT ep,POINT op) { return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y)); } double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离 { return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); } POINT p[50005]; POINT ans[50005]; bool cmp(const POINT& a,const POINT& b)//P[0]指PointSet { if ( multiply(a,b,p[0])>0 || // 极角更小 (multiply(a,b,p[0])==0) && //极角相等,距离更短 dist(p[0],a)<dist(p[0],b) ) return true; else return false; } void Graham_scan(POINT PointSet[],POINT ch[],int n,int &len) { int i,j,k=0,top=1; POINT tmp; // 选取PointSet中y坐标最小的点PointSet[k],如果这样的点有多个,则取最左边的一个 for(i=1;i<n;i++) if ( PointSet[i].y<PointSet[k].y || (PointSet[i].y==PointSet[k].y) && (PointSet[i].x<PointSet[k].x) ) k=i; tmp=PointSet[0]; PointSet[0]=PointSet[k]; PointSet[k]=tmp; // 现在PointSet中y坐标最小的点在PointSet[0] sort(PointSet+1,PointSet+n,cmp); ch[0]=PointSet[0]; ch[1]=PointSet[1]; for (i=2;i<n;i++) { while (top>0 &&multiply(PointSet[i],ch[top],ch[top-1])>=0) top--; ch[++top]=PointSet[i]; } len=top+1; } int max(int a,int b) { return a>b?a:b; } int cross(POINT a,POINT b,POINT o) { return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); } int dist2(POINT a,POINT b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } int rotating_calipers(POINT *ch,int n) { int q=1,ans=0; ch[n]=ch[0]; for(int p=0;p<n;p++) { while(cross(ch[p+1],ch[q+1],ch[p])>cross(ch[p+1],ch[q],ch[p])) q=(q+1)%n; ans=max(ans,max(dist2(ch[p],ch[q]),dist2(ch[p+1],ch[q+1]))); } return ans; } int main() { int i,j; int n; cin>>n; double x,y; for (i=0;i<n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); } int len=-1; Graham_scan(p,ans,n,len); printf("%d\n",rotating_calipers(ans,len)); return 0; }
凸包+暴力枚举:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=1e-5; double max(double a,double b) {return a>b?a:b;} double min(double a,double b) {return a<b?a:b;} struct POINT { double x; double y; POINT(double a=0, double b=0) { x=a; y=b;} //constructor }; struct LINESEG { POINT s; POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} LINESEG() { } }; struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0 { double a; double b; double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} }; double multiply(POINT sp,POINT ep,POINT op) { return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y)); } double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离 { return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); } POINT p[50005]; POINT ans[50005]; bool cmp(const POINT& a,const POINT& b)//P[0]指PointSet { if ( multiply(a,b,p[0])>0 || // 极角更小 (multiply(a,b,p[0])==0) && //极角相等,距离更短 dist(p[0],a)<dist(p[0],b) ) return true; else return false; } void Graham_scan(POINT PointSet[],POINT ch[],int n,int &len) { int i,j,k=0,top=1; POINT tmp; // 选取PointSet中y坐标最小的点PointSet[k],如果这样的点有多个,则取最左边的一个 for(i=1;i<n;i++) if ( PointSet[i].y<PointSet[k].y || (PointSet[i].y==PointSet[k].y) && (PointSet[i].x<PointSet[k].x) ) k=i; tmp=PointSet[0]; PointSet[0]=PointSet[k]; PointSet[k]=tmp; // 现在PointSet中y坐标最小的点在PointSet[0] sort(PointSet+1,PointSet+n,cmp); ch[0]=PointSet[0]; ch[1]=PointSet[1]; for (i=2;i<n;i++) { while (top>0 &&multiply(PointSet[i],ch[top],ch[top-1])>=0) top--; ch[++top]=PointSet[i]; } len=top+1; } int max(int a,int b) { return a>b?a:b; } int cross(POINT a,POINT b,POINT o) { return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); } int dist2(POINT a,POINT b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } int main() { int i,j; int n; cin>>n; double x,y; for (i=0;i<n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); } int len=-1; Graham_scan(p,ans,n,len); int maxx=0; for (i=0;i<len;i++) { for (j=i+1;j<len;j++) { __int64 tmp=(ans[i].x-ans[j].x)*(ans[i].x-ans[j].x); tmp+=(ans[i].y-ans[j].y)*(ans[i].y-ans[j].y); if (tmp>maxx) maxx=tmp; } } printf("%d\n",maxx); return 0; }