POJ - 2187 Beauty Contest (旋转卡壳求最远点对)

Description
Bessie, Farmer John’s prize cow, has just won first place in a bovine beauty contest, earning the title ‘Miss Cow World’. As a result, Bessie will make a tour of N (2 <= N <= 50,000) farms around the world in order to spread goodwill between farmers and their cows. For simplicity, the world will be represented as a two-dimensional plane, where each farm is located at a pair of integer coordinates (x,y), each having a value in the range -10,000 … 10,000. No two farms share the same pair of coordinates.

Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms.

Input

  • Line 1: A single integer, N

  • Lines 2…N+1: Two space-separated integers x and y specifying coordinate of each farm

Output

  • Line 1: A single integer that is the squared distance between the pair of farms that are farthest apart from each other.

Sample Input

4
0 0
0 1
1 1
1 0

Sample Output

2

Hint
Farm 1 (0, 0) and farm 3 (1, 1) have the longest distance (square root of 2)

题意:
求平面上的最远点对,本题数据不大求完凸包后坐标值最大n,则凸包最大顶点数n^0.5,可以暴力
n^2。但用旋转卡壳可达nlogn.

#include<iostream>
#include<string>
#include<map>
#include<algorithm>
#include<memory.h>
#include<cmath>
#define pii pair<int,int>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int Max = 1e6 + 5;
const int maxn = 1e6 + 5;
const double pi = acos(-1.0);
const double inf = 1e100;
const double eps = 1e-6;

struct Point {
   
    double x, y;
    Point(double x = 0, double y = 0) :x(x), y(y) {
   }
};
typedef Point Vector;
Point lst[maxn], stk[maxn];
int top;
Vector operator - (Point A, Point B) {
   
    return Vector(A.x - B.x, A.y - B.y);
}
int sgn(double x) {
   
    if (fabs(x) < eps)
        return 0;
    if (x < 0)
        return -1;
    return 1;
}
double Cross(Vector v0, Vector v1) {
   
    return v0.x * v1.y - v1.x * v0.y;
}
double Dis(Point p1, Point p2) {
    //计算 p1p2的 距离
    return sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
bool cmp(Point p1, Point p2) {
    //极角排序函数 ,角度相同则距离小的在前面
    int tmp = sgn(Cross(p1 - lst[0], p2 - lst[0]));
    if (tmp > 0)
        return true;
    if (tmp == 0 && Dis(lst[0], p1) < Dis(lst[0], p2))
        return true;
    return false;
}
double Dot(Vector A, Vector B) {
   
    return A.x * B.x + A.y * B.y;
}
double Length(Vector A) {
   
    return sqrt(Dot(A, A));
}
Vector Normal(Vector A) {
   //向量A左转90°的单位法向量
    double L = Length(A);
    return Vector(-A.y / L, A.x / L);
}
struct Line {
   
    Point p;//直线上任意一点
    Vector v;//方向向量,它的左边就是对应的半平面
    double ang;//极角,即从x轴正半轴旋转到向量v所需要的角(弧度)
    Line() {
   }
    Line(Point p, Vector v) : p(p), v(v) {
   
        ang = atan2(v.y, v.x);
    }
    bool operator < (const Line& L) const {
   //排序用的比较运算符
        return ang < L.ang;
    }
};
//点p在有向直线L的左侧
bool OnLeft(Line L, Point p) {
   
    return Cross(L.v, p - L.p) > 0;
}
//点的编号0 ~ n - 1
//返回凸包结果stk[0 ~ top - 1]为凸包的编号
void Graham(int n) {
   
    int k = 0;
    Point p0;
    p0.x = lst[0].x;
    p0.y = lst[0].y;
    for (int i = 1; i < n; ++i) {
   
        if ((p0.y > lst[i].y) || ((p0.y == lst[i].y) && (p0.x > lst[i].x))) {
   
            p0.x = lst[i].x;
            p0.y = lst[i].y;
            k = i;
        }
    }
    lst[k] = lst[0];
    lst[0] = p0;
    sort(lst + 1, lst + n, cmp);
    if (n == 1) {
   
        top = 1;
        stk[0] = lst[0];
        return;
    }
    if (n == 2) {
   
        top = 2;
        stk[0] = lst[0];
        stk[1] = lst[1];
        return;
    }
    stk[0] = lst[0];
    stk[1] = lst[1];
    top = 2;
    for (int i = 2; i < n; ++i) {
   
        while (top > 1 && Cross(stk[top - 1] - stk[top - 2], lst[i] - stk[top - 2]) <= 0)
            --top;
        stk[top] = lst[i];
        ++top;
    }
    return;
}

double Dist2(Point p1, Point p2) {
    //计算距离的平方
    double ret = Dot(p1 - p2, p1 - p2);
    return ret;
}
double RotatingCalipers(Point* ch, int m) {
   //返回平面最大距离的平方
    if (m == 1) return 0.0;
    if (m == 2) return Dist2(ch[0], ch[1]);
    double ret = 0.0;
    ch[m] = ch[0];
    int j = 2;
    for (int i = 0; i < m; ++i) {
   
        while (Cross(ch[i + 1] - ch[i], ch[j] - ch[i]) < Cross(ch[i + 1] - ch[i], ch[j + 1] - ch[i]))
            j = (j + 1) % m;
        ret = max(ret, max(Dist2(ch[j], ch[i]), Dist2(ch[j], ch[i + 1])));
    }
    return ret;
}

int main()
{
   
    int n;cin >> n;
    for (int i = 0;i < n;i++)
    {
   
        int a, b;cin >> a >> b;
        lst[i].x = a, lst[i].y = b;
    }
    Graham(n);
    int ans = RotatingCalipers(stk, top);
    cout << ans;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务