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

题目链接

求 $n$ 个点之间的最远点对距离平方

最远点对显然一定在 $n$ 个点内的凸包上,所以首先求出这 $n$ 个点间的凸包

得到凸包之后其实这道题目可以用 $O(n^{2})$ 的枚举暴力求出最远点对的距离平方

但是更优的做法是 $O(n)$ 复杂度的旋转卡壳算法

旋转卡壳算法的原理是用一对平行线在凸包外部卡住凸包不断地进行旋转

凸包上被一对平行卡壳正好卡住的对应点对称为对踵点(旋转卡壳——对踵点对(定义) ),所以我们可以不断地枚举边,找到此边得对踵点(对踵点到此边的距离一定最远)取距离最大值即可

利用此边两顶点外所有顶点与此边的三角形面积变化规律就可以求出此边得对踵点,三角形面积的变化为单峰函数,所以随着对应边的旋转最远点也会朝着相应的方向旋转,那么根据上一个对踵点便可向后寻找下一个对踵点,所以总时间复杂度为 $O(n)$

详解参考

【蒟蒻计算几何】旋转卡壳算法

AC代码:

// submit C++
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

typedef double db;
const int maxn = 5e4 + 5;
const db eps = 1e-9;

int Sgn(db Key) {return fabs(Key) < eps ? 0 : (Key < 0) ? -1 : 1;}
int Cmp(db Key1, db Key2) {return Sgn(Key1 - Key2);}
struct Point {
    db X, Y;
    Point() {}
    Point(db _X, db _Y) {
        X = _X;
        Y = _Y;
    }
};
typedef Point Vector;
Vector operator - (Vector Key1, Vector Key2) {return Vector(Key1.X - Key2.X, Key1.Y - Key2.Y);}
Vector operator + (Vector Key1, Vector Key2) {return Vector(Key1.X + Key2.X, Key1.Y + Key2.Y);}
db operator * (Vector Key1, Vector Key2) {return Key1.X * Key2.X + Key1.Y * Key2.Y;}
db operator ^ (Vector Key1, Vector Key2) {return Key1.X * Key2.Y - Key1.Y * Key2.X;}
db DisPointToPoint(Point Key1, Point Key2) {return sqrt((Key1 - Key2) * (Key1 - Key2));}
db DisPointToPoint2(Point Key1, Point Key2) {return (Key1 - Key2) * (Key1 - Key2);}
typedef vector<Point> Polygon;

int N;
Point points[maxn];
Polygon ConvexHull;
db Ans;

void RotateCaliper() {
    Ans = -1e20;
    if (ConvexHull.size() == 3) {
        if (Cmp(DisPointToPoint2(ConvexHull[0], ConvexHull[1]), Ans) > 0) Ans = DisPointToPoint2(ConvexHull[0], ConvexHull[1]);
        if (Cmp(DisPointToPoint2(ConvexHull[0], ConvexHull[2]), Ans) > 0) Ans = DisPointToPoint2(ConvexHull[0], ConvexHull[2]);
        if (Cmp(DisPointToPoint2(ConvexHull[1], ConvexHull[2]), Ans) > 0) Ans = DisPointToPoint2(ConvexHull[1], ConvexHull[2]);
        return;
    }
    int Cur = 2, Size = ConvexHull.size();
    for (int i = 0; i < Size; ++i) {
        while (Cmp(fabs((ConvexHull[i] - ConvexHull[(i + 1) % Size]) ^ (ConvexHull[Cur] - ConvexHull[(i + 1) % Size])), fabs((ConvexHull[i] - ConvexHull[(i + 1) % Size]) ^ (ConvexHull[(Cur + 1) % Size] - ConvexHull[(i + 1) % Size]))) < 0) Cur = (Cur + 1) % Size;
        if (Cmp(DisPointToPoint2(ConvexHull[i], ConvexHull[Cur]), Ans) > 0) Ans = DisPointToPoint2(ConvexHull[i], ConvexHull[Cur]);
    }
}

bool SortRule(const Point &Key1, const Point Key2) {
    db Temp = (Key1 - points[0]) ^ (Key2 - points[0]);
    if (Sgn(Temp) > 0) return true;
    else if (Sgn(Temp) == 0 && Cmp(DisPointToPoint(Key2, points[0]), DisPointToPoint(Key1, points[0])) > 0) return true;
    return false;
}

Polygon GrahamScan() {
    Polygon Ans;
    if (N < 3) {
        for (int i = 0; i < N; ++i) Ans.push_back(points[i]);
        return Ans;
    }
    int Low = 0;
    for (int i = 0; i < N; ++i)
        if (points[i].Y < points[Low].Y || (points[i].Y == points[Low].Y && points[i].X < points[Low].X))
            Low = i;
    swap(points[0], points[Low]);
    sort(points + 1, points + N, SortRule);
    Ans.push_back(points[0]);
    for (int i = 1; i < N; ++i) {
        while (Ans.size() >= 2 && Sgn((Ans.back() - Ans[Ans.size() - 2]) ^ (points[i] - Ans[Ans.size() - 2])) <= 0)
            Ans.pop_back();
        Ans.push_back(points[i]);
    }
    return Ans;
}

int main(int argc, char *argv[]) {
    scanf("%d", &N);
    for (int i = 0; i < N; ++i) scanf("%lf%lf", &points[i].X, &points[i].Y);
    ConvexHull = GrahamScan();
    if (ConvexHull.size() == 2) {
        printf("%.0lf\n", DisPointToPoint2(ConvexHull[0], ConvexHull[1]));
        return 0;
    }
    RotateCaliper();
    printf("%.0lf\n", Ans);
    return 0;
}
Last modification:March 27th, 2019 at 11:15 pm
如果觉得我的文章对你有用,请随意赞赏