1. 程式人生 > >poj 2187 計算幾何入門題 凸包

poj 2187 計算幾何入門題 凸包

連結:http://poj.org/problem?id=2187
題意:
有n個牧場,給定每個牧場的位置,位置互不相同,計算距離最遠的兩個牧場的之間的距離。
思路:
如果某個點在另外三個點組成的三角形的內部,那麼他就不屬於最遠點對。所以最後要考慮的就是所給點集中最外圍的點了。
這些最外圍的點的集合就是包含原點集的最小凸多邊形的頂點組成的集合,被稱為原點集的凸包。

求凸包的方法:
基於平面掃描的Graham掃描演算法:
1)將點集按照先x後y的字典序排序,這樣第一個和最後一個一定是凸包中的點。
2)分解為兩條鏈進行求解: 求解下側的鏈,從小到大處理點,構造凸包,在末尾加上新的頂點前,判斷是否會破壞凸性,如果會,則將凹的部分從凸包中取出。
2)求上鍊也是一樣的方法:從大到小處理。
排序複雜度O(nlogn) 求鏈O(n)
程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define M 50009
int n;
struct P
{
    double x,y;
    P(){}
    P(double x,double y) :x(x),y(y){}
    P operator - (P p)
    {
        return
P(x-p.x,y-p.y); } double det(P p) { return x*p.y - y*p.x; } double dot(P p) { return x*p.x + y*p.y; } }; P ps[M]; bool cmp(P a,P b) { if(a.x != b.x ) return a.x < b.x; return a.y < b.y; } double dist(P a,P b) { return (a-b).dot(a-b); } void
slove() { //求凸包 sort(ps,ps+n,cmp); int k = 0; //頂點個數 vector<P> qs(n*2); for(int i = 0;i < n;i++) //構造下側 { while(k > 1 && (ps[i]-qs[k-1]).det(qs[k-2]-qs[k-1]) <= 0) k--; qs[k++] = ps[i]; } for(int i = n-2, t = k;i > 0;i--) //構造上側,要從n-2開始因為n-1這個點一定已經在下鏈中包含進去了。。0這個點也在上鍊中包含了。。 { while(k > t && (ps[i]-qs[k-1]).det(qs[k-2]-qs[k-1]) <= 0) k--; qs[k++] = ps[i]; } qs.resize(k); double ans = 0; for(int i = 0;i < qs.size();i++) { for(int j = 0;j < i;j++) { ans = max(ans,dist(qs[i],qs[j])); } } printf("%.0f\n",ans); } int main() { while(scanf("%d",&n) == 1) { for(int i = 0;i < n;i++) scanf("%lf %lf",&ps[i].x,&ps[i].y); slove(); } return 0; }