计算几何
内容太多(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)\)
标签:直线,复杂度,boldsymbol,times,vec,计算,几何,向量 From: https://www.cnblogs.com/Cindy-Li/p/18221912