1015 - 計算幾何之旋轉卡殼 - Beauty Contest(POJ 2187)
阿新 • • 發佈:2018-11-10
題意
給定 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; }