二维凸包学习笔记

模板题链接:https://www.luogu.org/problemnew/show/P2742

感觉比较详细的教程:https://www.luogu.org/blog/cyx-TombRaider/p2742-mu-ban-er-wei-tu-bao-by-hydranazis

求凸包有两种主要的方法:极角序、水平序

然而ysy在某咕网校说极角序容易挂……所以本人学了水平序求凸包的方法


先按坐标排序

找到左下角的点

我们把整个凸包分成上凸包和下凸包两部分求

对于每个点,先进栈

如果它进栈之后还是一个凸包的结构,我们就把它加入栈中

而后来如果该节点被判断为不是凸包上的点,就弹栈

最后算周长的时候两部分分开算,再相加。




代码:

首先是定义结构体存储点

#include <bits/stdc++.h>

using namespace std;

struct Point {
    double x, y;
} point[10010];

int n;
double ans;

需要用到的函数:

double dis(double xa, double ya, double xb, double yb) {
    return sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
}

double check(int i, int j, int k) {
    return (point[i].y - point[j].y) * (point[k].x - point[j].x) < (point[k].y - point[j].y) * (point[i].x - point[j].x);
}

dis返回两点间距离,check比较斜率(又因为斜率=tan(倾斜角),所以也就是在比较倾斜角)大小


排序的比较函数:

bool cmp(Point a, Point b) {
    return a.y == b.y ? a.x < b.x : a.y < b.y;
}

按照坐标排序,如果纵坐标不相等比较纵坐标否则比较横坐标,这样排序出来的第一个点肯定是左下角的点。


主程序:

int main() {
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> point[i].x >> point[i].y;
    }
    sort(point + 1, point + n + 1, cmp);
    stack < int > s;
    s.push(1); s.push(2);
    for(int i = 3; i <= n; i++) {
        while(s.size() > 1) {
            int k = s.top();
            s.pop();
            int k2 = s.top();
            s.push(k);
            if(check(k2, s.top(), i)) s.pop(); else break;
        }
        s.push(i);
    }
    int k = s.top();
    s.pop();
    while(!s.empty()) {
        ans += dis(point[k].x, point[k].y, point[s.top()].x, point[s.top()].y);
        k = s.top();
        s.pop();
    }
    s.push(1); s.push(2);
    for(int i = 3; i <= n; i++) {
        while(s.size() > 1) {
            int k = s.top();
            s.pop();
            int k2 = s.top();
            s.push(k);
            if(!check(k2, s.top(), i)) s.pop(); else break;
        }
        s.push(i);
    }
    k = s.top();
    s.pop();
    while(!s.empty()) {
        ans += dis(point[k].x, point[k].y, point[s.top()].x, point[s.top()].y);
        k = s.top();
        s.pop();
    }
    printf("%.2lf", ans);
    return 0;
}

学过了凸包就可以做旋转卡壳的题目了,然而遇到旋转卡壳的题目窝只会口胡,不会打码 = = 可见我还是太弱了QAQ以后再填坑吧

猜你喜欢

转载自www.cnblogs.com/iycc/p/10486517.html