计算几何

计算几何

内容太多(105 页 ppt 呢
故只写大纲和之前不知道的东西

基本模板

前置知识

向量

  • 基本运算(加减、数乘、点乘、叉乘)
  • 高维向量的运算
  • 相关计算(长度、夹角、面积……

  • 叉乘:\(\vec a \times \vec b=|\vec a||\vec b|\sin<\vec a ,\vec b>\)
    • 角度是有向的(从 \(\vec a\) 转到 \(\vec b\)
    • 几何意义:平行四边形的有向面积
    • 二维坐标计算:\(\vec a \times \vec b =x_ay_b-y_ax_b\)
  • n 维 n-1 个向量叉乘,结果是 n 维向量,系数是行列式
    \( \left|\begin{array}{cccc} x_1 & x_2 & \vec i\\ y_1 & y_2 & \vec j\\ z_1 & z_2 & \vec k \end{array}\right| \)
    • 二维:\(\vec u \times \vec u=(-y_u,x_u)\)
    • 三维:方向是法向量,大小是平四面积

基于向量的表示法

  • \(\boldsymbol p\)
  • 直线 \(\left(\boldsymbol p,\boldsymbol d\right)\)\(\boldsymbol p\) 是任意一点,\(\boldsymbol d\) 是方向(一般用单位向量)
  • 线段 \(\left(\boldsymbol p,\boldsymbol d\right)\)\(\boldsymbol p\) 是一个端点,\(\boldsymbol d\)\(\boldsymbol p\) 到另一个端点的位移
  • 多边形 \((\boldsymbol {p_1},\boldsymbol {p_2},\dots,\boldsymbol{p_n})\),一般逆时针记录端点
  • \((\boldsymbol{o},r)\)
  • 曲线:解析式

图形关系

点线

  • \(\boldsymbol{u}\) 在直线上:\((\boldsymbol{u}-\boldsymbol{p})\times \boldsymbol{d}=0\)
  • \(\boldsymbol{u}\) 在线段上:在直线上 & 横纵坐标在区间内
  • \(\boldsymbol{u},\boldsymbol{v}\) 在直线同侧:\(((\boldsymbol{u}-\boldsymbol{p})\times \boldsymbol{d})\times ((\boldsymbol{v}-\boldsymbol{p})\times \boldsymbol{d})>0\)

线线

平行

  • \(l_1\parallel l_2\)\(\boldsymbol{d_1}\times \boldsymbol{d_2}=0\)
  • \(l_1\)\(l_2\) 重合:平行且 \(\boldsymbol{p_2}\)\(l_1\)

相交

  • 快速排斥实验 & 跨立实验:判断线段是否有交
  • 求直线的交点:列直线方程代入求解\(\boldsymbol{u}=\boldsymbol{p_1}+k\boldsymbol{d_1}\)
    \(k=\dfrac{(\boldsymbol{p_2}-\boldsymbol{p_1})\times \boldsymbol{d_2}}{\boldsymbol{d_1}\times\boldsymbol{d_2}}\)

点 & 多边形

  • 先判去点在多边形边缘的情况
  • 从该点引出任意一条射线,统计与多边形相交的次数。若奇数,则点在多边形内
  • 对于射线经过多边形某边或某点的情况,规定射线上的点均在射线的同一侧

直线 & 圆

  • 圆心到直线距离判位置关系
  • 过圆心的垂线 \((\boldsymbol{o},\boldsymbol{d}\times \boldsymbol{d})\),求交得到垂足
  • 勾股算交点到垂足距离

圆圆

  • 圆心距离判位置关系
  • 交线方程 \(\to\) 线圆交点

基本计算

  • 点到直线距离 \(dis(\boldsymbol u,(\boldsymbol p,\boldsymbol d))=(\boldsymbol{u}-\boldsymbol{p})\times \boldsymbol{d}\)
  • 多边形面积:\(\frac{1}{2}|\sum \boldsymbol{p_i}\times \boldsymbol{p_{(i\bmod n) +1}}|\),绝对值在求和号外面
  • 旋转向量 \((\boldsymbol{a}\times (\sin\theta,\cos\theta),\boldsymbol{a}\cdot (\sin\theta,\cos\theta)),\theta\in[0,\pi]\)

极角排序

先判象限,同一象限按 \(\boldsymbol{u}\times\boldsymbol{v}\) 的正负判断。

int quadrant(const vector2d& u) {
    return (u.y < 0) << 1 | ((u.x < 0) ^ (u.y < 0));
}
bool polar_cmp(const vector2d& u, const vector2d& v) {
    int qu = quadrant(u);
    int qv = quadrant(v);
    if (qu != qv) return qu < qv;
    ll d = det(u, v);
    if (d) return d > 0;
    return norm2(u) < norm2(v);
}

二维凸包

Andrew 算法

  • 所有点按 x 为第一关键字,y 为第二关键字排序
  • 单调栈分别求上下凸壳
vector<poi> Andrew(vector<poi> p){
    vector<poi> q;int tl=0;
    sort(p.begin(),p.end());
    rep(i,0,p.size()-1){
        while(tl>1 && cross(q[tl-2],q[tl-1],p[i])<=0)
            q.pop_back(),--tl;
        q.push_back(p[i]);++tl;
    }
    int tmp=tl;
    per(i,p.size()-2,0){
        while(tl>tmp && cross(q[tl-2],q[tl-1],p[i])<=0)
            q.pop_back(),--tl;
        q.push_back(p[i]);++tl;
    }
    q.pop_back();return q;
}

Graham 算法

  • 钦定一个起点,所有点极角排序
  • 同样是单调栈
  • 一般不写

例题 [SHOI2012] 信用卡凸包

普通凸包板子 + 角上转一圈

闵可夫斯基和

另一类图形并(?

定义 \(C=\{a+b|a\in A,b\in B\}\)

从左下角开始,双指针扫,按照极角序依次加入每条边

vector<poi> minkowski(vector<poi> &a,vector<poi> &b){
    vector<poi> c{a[0]+b[0]};int pa=1,pb=1;
    a.push_back(a[0]),b.push_back(b[0]);
    while(pa<(int)a.size() || pb<(int)b.size()){
        if(pa<(int)a.size() && (pb==(int)b.size()||
            sgn((a[pa]-a[pa-1])^(b[pb]-b[pb-1]))>=0))
             c.push_back(c.back()+a[pa]-a[pa-1]),pa++;
        else c.push_back(c.back()+b[pb]-b[pb-1]),pb++;
    }
    return c;
}

例题 [JSOI2018] 战争

题目要判断是否存在 \(q+\boldsymbol{v}=p\)
移项得 \(\boldsymbol{v}=p-q\)
于是判断 \(\boldsymbol{v}\) 是否在 \(p,-q\) 的闵可夫斯基和内
钦定起点,二分极角得到 \(\boldsymbol{v}\) 对应边,判断是否和起点在同一方向

旋转卡壳

在枚举凸包的边的同时,维护其他需要的点

可以在线性复杂度内解决凸包直径、最小矩形覆盖等问题

例题 [HNOI2007] 最小矩形覆盖

结论:最小矩形覆盖一定包含凸包上的一条边

枚举这条边,维护 3 个最远点即可

注意初始最左边的点要先赋值成初始最右边的点再扫,否则动不了

半平面

一条直线和直线的一侧,包含直线为闭,不包含为开

定义:\(Ax+By+C\ge 0\)

在计算几何中用向量表示,统一为向量的左侧

半平面交

  • 加入边界(避免特判无穷大)
  • 极角排序(斜率相同,靠左的在前面)+ 去重
  • 单调队列维护(先弹队尾,再弹队首)
    • 弹出条件(以队尾为例)

      队尾的两直线交点在新直线右侧时,弹出队尾。
    • 改进精度(代入交点坐标,解方程,去分母)
    • \(((\boldsymbol{p_1}-\boldsymbol{p_3})\times\boldsymbol{d_3})(\boldsymbol{d_1}\times\boldsymbol{d_2})\ge ((\boldsymbol{p_1}- \boldsymbol{p_2})\times\boldsymbol{d_2})(\boldsymbol{d_1}\times \boldsymbol{d_3})\)
    • 先弹队尾,再弹队首,全部结束后用队首弹队尾

  • 判断无交
    • 若最后只有 \(<2\) 条线,一定无交
    • 任取两条线的交点,判断它是否在所有射线的左边
    • 特殊情况:存在平行且反向,互相在对方右侧的向量
      如果出现,其他向量一定被弹没,只需判断队尾和前一个即可
  • 求面积就是平凡的多边形

随机增量法

增量法:将一个问题化为刚好小一层的子问题
\(T(n)=T(n-1)+g(n)\)

例题:Luogu 1742 最小圆覆盖

  • 求三个点的外接圆:垂直平分线
  • 增量构造
    • 前 i-1 个点的圆是 \(C\),若 i 在 \(C\) 中,跳过
    • 否则 i 一定在新的 \(C'\)
    • 重复找第一个不在圆 \(C'\) 中的点,让圆 \(C'\) 过这个点
  • 感性理解,最后一定能构造出前 i 个点的圆,因为不会出现两个点在 i “两端”的情况(否则 i 就在 \(C\) 中)
  • 复杂度分析:
    • 由于最多只有 3 个点参与确定了最小覆盖圆,每个点参与的概率不大于 \(\frac{3}{n}\),也就是每层会循环到下一层的概率不大于 \(\frac{3}{i}\)
    • \(T_1(n)=O(n)+\sum \frac{3}{i}T_2(i)\)
    • \(T_2(n)=O(n)+\sum \frac{3}{i}T_3(i)\)
    • \(T_3(n)=O(n)\)
    • 显然 \(T_1(n)=T_2(n)=T_3(n)=O(n)\),带有一个大概 13 的常数

平面图转对偶

定义:原图每个面对应一个点,每条边左右的面连起来。

(虽然很丑但它是对偶图/kk

  • 认为每个面是由逆时针的有向边拼起来的
  • 原图中的边拆成两条有向边(对应两个面)
  • 枚举每条边,若还没访问过,就从它出发逆时针转,找原图中它左边的面
  • 对原图中每个点,从它出发的有向边极角排序
  • 下一个要访问的边,就是当前边的反向边在极角序中的前驱
  • 最后连接每条边对应的两个面

例题:Luogu 3249 矿区

先转对偶图,随便找一颗生成树,以无界域为根

非常厉害的结论:

多边形边界对应的树边,若内部是儿子,加上子树权值;否则,减去子树权值

画图可以感受到这个容斥是正确的,并适用于一切可加减的信息

习题

Luogu 3517 WYK-Plot

给定 n 个点,要求分成不超过 m 段,最小化每段最小覆盖圆的半径最大值。

二分答案,关键在于 check

我们不可以按顺序增量构造,因为随机增量复杂度才是对的。

从左到右构造,每个左端点找最大右端点,如果二分范围 [l,n],复杂度会悲催的成为 \(O(n^2\log n)\)

key: 倍增优化二分

考虑倍增段长找到第一个不符合要求的 \(R\),如果最终答案为 \(r\),显然倍增的复杂度不超过 \(2(r-l)\)

\([l,R]\) 区间来二分,check 的复杂度就是 \(O(n\log n)\) 了。

加上二分答案的复杂度,最终复杂度是 \(O(n\log^2 n)\)

posted @ 2024-11-19 15:35  Cindy_Li  阅读(76)  评论(0)    收藏  举报