• 二维凸包学习笔记


    模板题链接: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以后再填坑吧

  • 相关阅读:
    编译内核开始的小问题Unable to find the Ncurses libraries
    qq for linux Ubuntu 64位兼容
    ubuntu下安装lighttpd
    搭建boa服务器
    INI file and Iniparser
    kernel常用.gitignore配置
    光谱学习
    jump to case label fpermissive
    Qt通用方法及类库5
    Qt通用方法及类库1
  • 原文地址:https://www.cnblogs.com/iycc/p/10486517.html
Copyright © 2020-2023  润新知