POJ2187-Beauty Contest- 最远点对问题(凸包+旋转卡壳)

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;
	
}


你可能感兴趣的:(POJ2187-Beauty Contest- 最远点对问题(凸包+旋转卡壳))