第六章---计算几何

文章目录

    • 六、计算几何
      • [6.1 基础几何模板](#6.1 基础几何模板)
      • [6.2 点到线段距离 / 线段相交](#6.2 点到线段距离 / 线段相交)
      • [6.3 凸包(Andrew 算法)](#6.3 凸包(Andrew 算法))

六、计算几何

6.1 基础几何模板

cpp 复制代码
class Solver {
public:
    const double eps = 1e-8;
    const double PI = acos(-1.0);
    int sign(double x) {
        if (fabs(x) < eps) return 0;
        return x < 0 ? -1 : 1;
    }
    struct Point {
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) {}
        Point operator+(Point b) { return Point(x + b.x, y + b.y); }
        Point operator-(Point b) { return Point(x - b.x, y - b.y); }
        Point operator*(double k) { return Point(x * k, y * k); }
        double operator*(Point b) { return x * b.x + y * b.y; }  // 点积
        double operator^(Point b) { return x * b.y - y * b.x; }  // 叉积
        double len() { return sqrt(x*x + y*y); }
        double len2() { return x*x + y*y; }
    };
    // 叉积:ab × ac
    double cross(Point a, Point b, Point c) {
        return (b - a) ^ (c - a);
    }
    // 点积:ab · ac
    double dot(Point a, Point b, Point c) {
        return (b - a) * (c - a);
    }
    // 两点距离
    double dist(Point a, Point b) {
        return (a - b).len();
    }
};

思路要点:

  • 点积:判断夹角(锐角/钝角/垂直)、投影长度
  • 叉积:判断转向(顺/逆时针)、平行四边形面积
  • 浮点比较用 sign 函数,避免精度问题

6.2 点到线段距离 / 线段相交

cpp 复制代码
class Solver {
public:
    // 点p到线段ab的距离
    double point_to_seg(Point p, Point a, Point b) {
        if (sign(dot(a, b, p)) < 0) return dist(p, a);
        if (sign(dot(b, a, p)) < 0) return dist(p, b);
        return fabs(cross(a, b, p)) / dist(a, b);
    }
    // 判断线段相交(规范相交)
    bool seg_intersect(Point a1, Point a2, Point b1, Point b2) {
        double c1 = cross(a1, a2, b1), c2 = cross(a1, a2, b2);
        double c3 = cross(b1, b2, a1), c4 = cross(b1, b2, a2);
        return sign(c1) * sign(c2) < 0 && sign(c3) * sign(c4) < 0;
    }
};

6.3 凸包(Andrew 算法)

cpp 复制代码
class Andrew {
public:
    vector<Point> convex_hull(vector<Point> p) {
        int n = p.size(), k = 0;
        if (n <= 1) return p;
        sort(p.begin(), p.end(), [](Point a, Point b) {
            return sign(a.x - b.x) ? a.x < b.x : a.y < b.y;
        });
        vector<Point> res(n * 2);
        // 下凸壳
        for (int i = 0; i < n; res[k++] = p[i++])
            while (k >= 2 && sign(cross(res[k-2], res[k-1], p[i])) <= 0) k--;
        // 上凸壳
        for (int i = n - 2, t = k + 1; i >= 0; res[k++] = p[i--])
            while (k >= t && sign(cross(res[k-2], res[k-1], p[i])) <= 0) k--;
        res.resize(k - 1);
        return res;
    }
};

思路要点:

  • 按 x 排序,x 相同按 y
  • 从左到右扫下凸壳,右到左扫上凸壳
  • 栈内维护凸性,不满足则弹出
  • 时间复杂度 O(n log n)

相关推荐
喵本喵叁肆6 小时前
用 Boosting 把弱隐私算法炼成强隐私算法(英文原题:Boosting and Differential Privacy (FOCS 2010))
算法·集成学习·boosting
青梅味猪大肠6 小时前
【操作系统-60】临近适应算法
java·linux·开发语言·嵌入式硬件·算法·操作系统
FakeOccupational6 小时前
【电路笔记 STM32】RTC配置:晶振选择+闹钟Configuration+中断设置
笔记·stm32·实时音视频
迪康coolmu6 小时前
企业U盘管控落地实战:基于迪康端点安全一体化管理系统的移动存储安全实践
运维·人工智能·经验分享·笔记·安全·电脑
Z21-X9 小时前
云原生运维学习笔记:容器技术的演进、底层原理与 Docker 全生命周期管理
运维·笔记·学习·云原生
Rabitebla17 小时前
【Linux 底层原理】进程(十):进程等待详解---从僵尸进程到 wait、waitpid 与 status
linux·c++·笔记·学习·visual studio
小lu飞18 小时前
2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程
前端·笔记·ai·ai编程
其实防守也摸鱼21 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
Nuanyt21 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表