Andrew algorithm (convex hull construction)

brief

This is a group \ (\ Graham) and an algorithm thinking, I personally think wherein the improvement complexity should be in the \ (sort \) is \ (cmp \) part of it,
\ (Graham \) is \ (cmp \ ) Part needs to calculate the cross product of two points, and even calculate the distance between the two points in some cases. This step should be relatively complicated.
And \ (Andrew \) avoids this step very well. You can implement a \ (nlogn \) algorithm by simply sorting the points \ (x, y \)

Algorithm idea

  • First of all, we need to sort all the points, usually according to, \ (X \) from small to large, if \ (X \) is equal, according to \ (Y \) from small to large.
    Here we must understand that after sorting, the first and last points must be extreme points.

  • Then there is the important step of \ ( Graham \) algorithm \ (Scan \) .
    The first pass \ (Scan \) we start from the leftmost point, do it again \ (Scan \) we can get the lower part of the entire convex hull.
    In the second pass \ (Scan \), we start from the rightmost point, and once we do \ (Scan \), we can get the upper part of the entire convex hull.
    The combination of these two \ (Scan \) is a complete convex hull.

Implementation legend

This is the first time \ (Scan \) . The blue one has walked, but it has been traced back because of the contradiction with the points behind it. The red line represents the level of the scan that satisfies the condition, that is, the edge that forms the lower half of the convex hull.

This is the second pass of \ (Scan \) . The green representative once walked, but did a backtracking because of the contradiction with the points behind it. The black line represents the level of the scan that satisfies the condition, that is, the edge that constitutes the upper half of the convex hull.

Time complexity analysis

The time of \ (sort \) is \ (O (nlogn) \) The time of two trips \ (scan \) is linear, the complexity of the site preparation is \ (O (nlogn) \) , but we think the time of this algorithm The complexity is better than \ (graham \) , the reason should be that I mentioned at the beginning

Template questions

P2742 [USACO5.1] Fencing the Cows / 【Template】 Two-dimensional convex hull

\ (Debug \) very messy code during learning

/*
    Code by lifehappy 2020:04:17
    凸包Andrew算法
*/
#include<bits/stdc++.h>
using namespace std;
const double INF = 1e100;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int N = 1e5 + 10;

int n, cnt, m;

int sgn(double x) {
    if(fabs(x) < eps)   return 0;
    if(x > 0)   return 1;
    return -1;
}
struct point {
    double x, y;
    point(double a = 0.0, double b = 0.0) : x(a), y(b) {}
    bool operator < (point t) {
        if(sgn(x - t.x) == 0)    return y < t.y;
        return x < t.x;
    }
}p[N], ans[N], all[N];

point operator - (point a, point b) {
    return point(a.x - b.x, a.y - b.y);
}
double dis(point a, point b) {
    a = a - b;
    return sqrt(a.x * a.x + a.y * a.y);
}
double cross(point a, point b) {
    return a.x * b.y - a.y * b.x;
}

void Andrew() {
    sort(p, p + n);
    int p1 = 0, p2;
    for(int i = 0; i < n; i++) {
        while(p1 > 1 && sgn(cross(ans[p1 - 1] - ans[p1 - 2], p[i] - ans[p1 - 2])) == -1)   p1--;
        ans[p1++] = p[i];
    }
    // cout << p1 << endl;
    // for(int i = 0; i < p1; i++) {
    //     int flag = 1;
    //     for(int j = 0; j < m; j++)
    //         if(sgn(ans[i].x - all[j].x) == 0 && sgn(ans[i].y - all[j].y) == 0) {
    //             flag = 0;
    //             break;
    //         }
    //     printf("%lf %lf    %s\n", ans[i].x, ans[i].y, flag ? "False" : "            True");
    // }
    // cout << p1 << endl;
    p2 = p1;
    for(int i = n - 2; i>= 0; i--) {
        while(p2 > p1 && sgn(cross(ans[p2 - 1] - ans[p2 - 2], p[i] - ans[p2 - 2])) == -1)  p2--;
        ans[p2++] = p[i];
        // cout << p2 << endl;
    }
    // for(int i = 0; i < p2; i++)
    //     printf("%lf %lf\n", ans[i].x, ans[i].y);
    // p2--;
    p2--;
    // for(int i = p1; i < p2; i++) {
    //     int flag = 1;
    //     for(int j = 0; j < m; j++)
    //         if(sgn(ans[i].x - all[j].x) == 0 && sgn(ans[i].y - all[j].y) == 0) {
    //             flag = 0;
    //             break;
    //         }
    //     printf("%lf %lf    %s\n", ans[i].x, ans[i].y, flag ? "False" : "            True");
    // }
    // cout << p2 << endl;
    double target = 0.0;
    for(int i = 0; i < p2; i++)
        target += dis(ans[i], ans[i + 1]);
    printf("%.2f\n", target);
}
int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // scanf("%d", &m);
    // for(int i = 0; i < m; i++)
    //     scanf("%lf %lf", &all[i].x, &all[i].y);
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%lf %lf", &p[i].x, &p[i].y);
    Andrew();
    // point a(-9934.480000, -2886.200000), b(-9595.260000, -1905.480000), c(-9124.100000, -4804.250000);
    // printf("%lf\n", cross(b - a, c - a));
    return 0;
}

Cleaner code

/*
    Code by lifehappy 2020:04:17
    凸包Andrew算法
*/
#include<bits/stdc++.h>
using namespace std;
const double INF = 1e100;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int N = 1e5 + 10;

int n, cnt, m;

int sgn(double x) {
    if(fabs(x) < eps)   return 0;
    if(x > 0)   return 1;
    return -1;
}
struct point {
    double x, y;
    point(double a = 0.0, double b = 0.0) : x(a), y(b) {}
    bool operator < (point t) {
        if(sgn(x - t.x) == 0)    return y < t.y;
        return x < t.x;
    }
}p[N], ans[N], all[N];

point operator - (point a, point b) {
    return point(a.x - b.x, a.y - b.y);
}
double dis(point a, point b) {
    a = a - b;
    return sqrt(a.x * a.x + a.y * a.y);
}
double cross(point a, point b) {
    return a.x * b.y - a.y * b.x;
}

void Andrew() {
    sort(p, p + n);
    int p1 = 0, p2;
    for(int i = 0; i < n; i++) {
        while(p1 > 1 && sgn(cross(ans[p1 - 1] - ans[p1 - 2], p[i] - ans[p1 - 2])) == -1)   p1--;
        ans[p1++] = p[i];
    }
    p2 = p1;
    for(int i = n - 2; i>= 0; i--) {
        while(p2 > p1 && sgn(cross(ans[p2 - 1] - ans[p2 - 2], p[i] - ans[p2 - 2])) == -1)  p2--;
        ans[p2++] = p[i];
    }
    p2--;
    double target = 0.0;
    for(int i = 0; i < p2; i++)
        target += dis(ans[i], ans[i + 1]);
    printf("%.2f\n", target);
}
int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%lf %lf", &p[i].x, &p[i].y);
    Andrew();
    return 0;
}

Guess you like

Origin www.cnblogs.com/lifehappy/p/12721746.html