1. 程式人生 > >1015 - 計算幾何之旋轉卡殼 - Beauty Contest(POJ 2187)

1015 - 計算幾何之旋轉卡殼 - Beauty Contest(POJ 2187)

傳送門

 

題意

給定 n 個點,求最遠點對,並輸出其距離的平方

 

分析

首先我們先來把這  n 個點圍出一個凸包來

由於最遠點對肯定不會在凸包內部啊,所以我們就在凸包邊上找找找找找

用一個叫做旋轉卡殼的演算法,我們可以在凸包頂點數的線性時間內求得最遠點對

具體是怎麼搞的呢?

可以想象有兩條平行線,“卡”住這個凸包,然後卡緊的情況下旋轉一圈,肯定就能找
到凸包直徑,也就找到了最遠的點對。

(雖然我還不太清楚這個演算法的正確性,但……秉持著先吸收再理解的原則,我們先死記一下吧)

來咯~

我們來瞧瞧程式碼吧

 

程式碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m;
struct point {
	int x,y;
	point(){}
	point(int _x,int _y):x(_x),y(_y){}
	friend inline point operator +(const point &a,const point &b){
		return point(a.x+b.x,a.y+b.y);
	}
	friend inline point operator -(const point &a,const point &b){
		return point(a.x-b.x,a.y-b.y);
	}
	friend inline point operator *(int k,const point &a){
		return point(a.x*k,a.y*k);
	}
	friend inline int dot(const point &a,const point &b){
		return a.x*b.x+a.y*b.y;
	}
	friend inline int cross(const point &a,const point &b){
		return a.x*b.y-a.y*b.x;
	}
}a[50009],b[50009],S;
bool cmp1(const point &a,const point &b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const point &a,const point &b){
	int hh=cross(a-S,b-S);
	if(hh==0) return dot(a-S,a-S)<dot(b-S,b-S);
	return hh>0;
}
void Graham(){
	sort(a+1,a+n+1,cmp1);
	S=a[1];b[m=1]=a[1];
	sort(a+2,a+n+1,cmp2);
	for(int i=2;i<=n;++i)
	{
		while(m>=2&&cross(a[i]-b[m-1],b[m]-b[m-1])>=0) --m;
		b[++m]=a[i];
	}
}
int nxt(int x){
	if(x+1>m) return 1;
	return x+1;
}
int Area(const point &a,const point &b,const point &c){
	return cross(b-a,c-a);
}
int solve(){
	int i=1,j=3,res=0;
	b[m+1]=b[1];
	for(;i<=m;++i){
		while(nxt(j)!=i&&Area(b[i],b[i+1],b[j])<=Area(b[i],b[i+1],b[j+1])) j=nxt(j);
		int hh=dot(b[j]-b[i],b[j]-b[i]),hh2=dot(b[j]-b[i+1],b[j]-b[i+1]);
		if(res<hh) res=hh;
		if(res<hh2) res=hh2;
	}
	return res;
}
int main(){
	scanf("%d",&n);
	int i,j,k;
	for(i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y);
	Graham();
	int ans=solve();
	printf("%d",ans);
	return 0;
}