POJ 2187 Beauty Contest (旋转卡壳)

题意

给定二维平面 n n n个点,求两点的最大距离。


思路

模板题, g r a h a m graham graham扫描+ r o t a t i n g   c a l i p e r s rotating\ calipers rotating calipers。

旋转卡壳(xuan zhuan qia ke)

时间复杂度: O ( n l o g n + n ) O(nlogn+n) O(nlogn+n)


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
const double pi=acos(-1.0);
int n,top;
struct P{
	double x,y;
}a[N],s[N];//s[]储存凸包上的点栈
double cross(P a,P b,P c){	//叉积
	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dis(P a,P b){	//距离的平方 
	return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(P u,P v){	//极角排序
	double t=cross(u,v,a[1]);
	if(t<0||(t==0&&dis(u,a[1])>dis(v,a[1]))) return 0;return 1;
} 
void graham(){	//构造凸包 
	sort(a+2,a+n+1,cmp);//极角排序
	s[++top]=a[1],s[++top]=a[2];//加入第二个点.
	for(int i=3;i<=n;){//栈维护凸包
	//	printf("%f\n",cross(s[top-1],a[i],s[top]));
		if(top>1&&cross(s[top-1],a[i],s[top])>=0) --top;//这里top>1 因为第一个点肯定是凸包上的点不用弹出 
		else s[++top]=a[i++];
	}	
}
double rt_cp(){	//rotating calipers(旋转卡壳) 
	if(top==2) return dis(s[1],s[2]); //共线情况
	s[top+1]=s[1];int j=2;double ans=0;
	for(int i=1;i<=top;i++){
		while(fabs(cross(s[i],s[i+1],s[j]))<fabs(cross(s[i],s[i+1],s[j+1]))) j=j%top+1;
		ans=max(ans,dis(s[i],s[j]));
	}return ans;
} 
int main(){
	while(~scanf("%d",&n)&&n){
		a[0].x=a[0].y=inf;int id;
		top=0;
		for(int i=1;i<=n;i++){
			scanf("%lf%lf",&a[i].x,&a[i].y);
			if(a[i].x<a[0].x||(a[i].x==a[0].x&&a[i].y<a[0].y)) a[0]=a[i],id=i; 
		}swap(a[1],a[id]); //先找到左下角的点,这个点一定是凸包上的点.
		graham();
		printf("%.0f\n",rt_cp()); 
	}
	return 0;
}