POJ - 2187 Beauty Contest (求距離最遠點對-凸包+旋轉卡殼/枚舉 (旋轉卡殼學習))

鏈接:https://vjudge.net/problem/POJ-2187

題意:求求距離最遠點對。

思路:肯定爲凸包上的點,可枚舉,也可根據凸包性質旋轉卡殼求對踵點

參考博客:

https://www.cnblogs.com/xdruid/archive/2012/07/01/2572303.html

https://blog.csdn.net/ACMaker/article/details/3177045

旋轉卡殼詳解:https://blog.csdn.net/ACMaker

1.凸包+枚舉 313ms

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 5e4+10;
const double eps = 1e-8;
int sgn(double x)
{
	if(fabs(x)<eps) return 0;
	else if(x<0) return -1;
	else return 1;
}
struct Point
{
	ll x,y;
	Point(){}
	Point(ll x,ll y):x(x),y(y){}
	Point operator -(const Point& b)const//相減 
	{
		return Point(x-b.x,y-b.y);
	}
	ll operator ^(const Point& b)const//叉乘 
	{
		return x*b.y-y*b.x;
	}
	ll operator *(const Point& b)const//點乘 
	{
		return x*b.x+y*b.y;
	}		
}ps[N],st[N];
int n,pos,top;
ll x,ans;
bool cmp(const Point& a,const Point& b)
{
	x=(a-ps[1])^(b-ps[1]);
	if(x==0)
	{
		if(a.y==b.y)
			return a.x<b.x;
		else return a.y<b.y;
	}
	else if(x>0) return 1;
	else return 0;
}
bool check(Point a,Point b,Point c)
{
	x=(b-a)^(c-a);
	return x<=0;
}
void getconv()
{
	top=2;
	st[1]=ps[1];
	st[2]=ps[2];
	for(int i=3;i<=n;i++)
	{
		while(top>2&&check(st[top-1],st[top],ps[i])) 
			top--;			
		st[++top]=ps[i];
	}	
} 
ll dis(Point a,Point b)
{
	return (a-b)*(a-b);
}
int main(void)
{
	while(~scanf("%d",&n))
	{	
		pos=1;		
		for(int i=1;i<=n;i++)
		{
			scanf("%lld%lld",&ps[i].x,&ps[i].y);
			if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
				pos=i;
		}
		swap(ps[1],ps[pos]);
		sort(ps+2,ps+n+1,cmp);
		getconv();
		ans=0;
		for(int i=1;i<=top;i++)
			for(int j=i+1;j<=top;j++)
				ans=max(ans,dis(st[i],st[j]));
		printf("%lld\n",ans);	
	}
	return 0;
}

2.凸包+旋轉卡殼

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 5e4+10;
const double eps = 1e-8;
int sgn(double x)
{
	if(fabs(x)<eps) return 0;
	else if(x<0) return -1;
	else return 1;
}
struct Point
{
	ll x,y;
	Point(){}
	Point(ll x,ll y):x(x),y(y){}
	Point operator -(const Point& b)const//相減 
	{
		return Point(x-b.x,y-b.y);
	}
	ll operator ^(const Point& b)const//叉乘 
	{
		return x*b.y-y*b.x;
	}
	ll operator *(const Point& b)const//點乘 
	{
		return x*b.x+y*b.y;
	}		
}ps[N],st[N];
int n,pos,top;
ll x;
bool cmp(const Point& a,const Point& b)
{
	x=(a-ps[0])^(b-ps[0]);
	if(x==0)
	{
		if(a.y==b.y)
			return a.x<b.x;
		else return a.y<b.y;
	}
	else if(x>0) return 1;
	else return 0;
}
bool check(Point a,Point b,Point c)
{
	x=(b-a)^(c-a);
	return x<=0;
}
void getconv()//求凸包 
{
	st[0]=ps[0];
	st[1]=ps[1];
	top=1;
	for(int i=2;i<n;i++)
	{
		//逆時針必須向左轉 
		while(top>1&&check(st[top-1],st[top],ps[i])) 
			top--;			
		st[++top]=ps[i];
	}	
} 
ll dis(Point a,Point b)
{
	return (a-b)*(a-b);
}
ll RC()//旋轉卡殼
{

	if(top==1) return dis(st[0],st[1]);
	ll ans=0;
	int j=2;
	st[++top]=st[0];
	for(int i=0;i<top;i++)
	{
		//找距離邊最遠的點 
		while(((st[i]-st[j])^(st[i+1]-st[j]))<((st[i]-st[j+1])^(st[i+1]-st[j+1])))
			j=(j+1)%top;
		//點對爲其一 
		ans=max(ans,max(dis(st[i],st[j]),dis(st[i+1],st[j])));	
	}
	return ans;
} 
int main(void)
{
	while(~scanf("%d",&n))
	{	
		pos=0;		
		for(int i=0;i<n;i++)
		{
			scanf("%lld%lld",&ps[i].x,&ps[i].y);
			if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
				pos=i;
		}
		swap(ps[0],ps[pos]);
		sort(ps+1,ps+n,cmp);
		getconv();
		printf("%lld\n",RC());	
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章