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