POJ 2187(凸包GrahamScan扫描+极角排序+平面最远点对)

Language:
平面最远点对
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 22454   Accepted: 6868

Description

求 N (2 <= N <= 50,000) 个点平面最远点对距离平方. 

Input

* 第1行:N 

接下来每行为点的坐标 x 和 y ,(x,y)(-10,000<=x,y<=10,000的整数). 

Output

输出一行,为平面最远点对距离平方. 

Sample Input

4
0 0
0 1
1 1
1 0

Sample Output

2

Hint

(0, 0) a到 (1, 1) 距离平方为 2 

Source

凸包模版题

先用GrahamScan扫描求凸包,显然最远点对在凸包上。


极角排序:

按照逆时针顺序给平面上的点集到一个点的距离排序,使得排序后所有点正好绕这个点一圈.(按距离远近从小到大排

思路:


GrahamScan扫描:







大致如此.


另补:

该题小Bug-有可能所有点在一条直线上。

这样也能求出:

Ex:

a序列(-1,0) (0,0)    (4,0)   (9,0)

则st序列重复如下操作:

(-1,1),(0,0)入队。

(4,0)入队,不左拐->(0,0)出队

队列元素<2 (4,0)入队

……


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (50000+10)
double sqr(double x){return x*x;}
struct P
{
    double x,y;
    P(){}
    P(double _x,double _y):x(_x),y(_y){}
}a[MAXN],st[MAXN];
int dis2(P A,P B)
{
    return sqr(A.x-B.x)+sqr(A.y-B.y);
}
double dis(P A,P B)
{
    return sqrt(double(dis2(A,B)));
}
struct V
{
    double x,y;
    V(){}
    V(double _x,double _y):x(_x),y(_y){}
    V(P A,P B):x(B.x-A.x),y(B.y-A.y){}
};
double operator*(V a,V b)
{
    return a.x*b.y-a.y*b.x;
}
int cmp(P A,P B) //1:a>b 0:a<=b
{
    double tmp=V(a[1],A)*V(a[1],B);
    if (tmp>0) return 1;
    else if (tmp==0) return (-(dis(a[1],A)-dis(a[1],B))>0)?1:0;
    else return 0;
}
int n;
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
    int p=1;
    for (int i=2;i<=n;i++) if (a[i].x<a[p].x||a[i].x==a[p].x&&a[i].y<a[p].y) p=i;
    if (p>1) swap(a[p],a[1]);
    sort(a+2,a+1+n,cmp);

    int size=1;
    st[1]=a[1];
    for (int i=2;i<=n;)
        if (size<2||V(st[size-1],st[size])*V(st[size],a[i])>0)
            st[++size]=a[i++];
        else size--;

    int ans=0;  
    for (int i=1;i<size;i++)
        for (int j=i+1;j<=size;j++)
            ans=max(ans,dis2(st[i],st[j]));
    cout<<ans<<endl;

    return 0;
}