计算几何

误差分析

比如点的范围是 \(w\),那么斜率/极角误差要到 \(w^{-2}\)

比如 \(w=10^9\),选取点 \((10^9,1)~(10^9-1,1)\),就可以估算范围是 \(\frac{1}{10^9-1}-\frac{1}{10^9}=\frac{1}{10^{18}}\)

\(\operatorname{double}\) 最大 \(~2^{1024}\) 精度 \(10^{-15}\)
\(\operatorname{long double}\) 最大 \(~2^{2^{16}}\) 精度 \(10^{-18}\)

基本工具

点积 Dot

判断角度,大于零为锐角,等于零为直角,小于零为钝角。

同时可以判断向量方向,正 OR 反。

求向量长度的时候,自己点积自己然后开方即可。

叉积 Cross

有向角 \(\theta\),注意点积有交换律,叉积没有。

可以判断一些相对位置

\(P_1\times P_2>0\)\(P_2\)\(P_1\) 逆时针方向。
\(P_1 \times P_2=0\),共线,此时可以再用点积判断同向还是异向。
\(P_1 \times P_2<0\)\(P_2\)\(P_1\) 顺时针方向。

同时表示有向面积,逆时针面积为正。

极角排序

极角,\(\theta \in [-\pi,\pi)\)

double 版本可以用函数 atan2(y,x),如果是 long double 版本就是 atan2l

但是精度和速度不太好。于是这里可以用 cmp 函数,用叉积判断逆时针和顺时针。先判断两点在上下半边的哪里,如果(y==0&&x<0)||y<0就是在下办边,反之在上半边。如果在一边的话用叉积判断相对位置即可。

QOJ9503.Rikka with Triangles

给定平面上 \(n\) 个点,求所有锐角三角形的总面积,保证无三点共线,\(n\le 2000\)\(|x_i|,|y_i|\le 10^{18}\)

锐角三角形不好求,因为你需要满足三个角都是锐角。但是很好判定直角三角形和钝角三角形,所以统计这些三角形的面积,再拿总面积减去即可。

可以通过极角排序之后,双指针统计贡献。

P10671 BZOJ1278 向量 vector

双倍经验:P5955 [POI 2018] Pionek

凸包

给出一些点,求可以包含这些点的最小多边形,即为凸包。

P2742【模板】二维凸包

二维凸包求法模板题。按照 \((x,y)\) 双关键字升序排序后先求下凸壳,再求上凸壳。

先是循环从头开始,每次不断加点,同时用叉积判断不合法的点弹出,求出下凸壳之后,从倒数第二个元素开始倒着循环,因为最后一个元素必然在求下凸壳的时候已经加入了。对于第一个元素的处理就要注意了,由于其在上凸壳中也被加过了,所以直接的想法是倒着循环到最后不枚举它了,但是这是错的, 因为你在弹栈的时候可能会依赖这个点弹出若干不合法点,如果不枚举它了就无法弹出不合法点了,正确做法是做完一遍之后弹出最后一个点,因为它必然被在开头和结尾各加了一次。同时注意上凸壳弹栈的时候必须保留上凸壳的那些不能弹。

用点积判断角度的时候,如果是严格凸包的话,等于要去掉。不严格的可以取等。

注意:如果有重点求不严格凸包会出问题,需要去重

QOJ7906. Almost Convex

给定 \(n\) 个点,它们的凸包大小为 \(R\)。求有多少个大小 \(\le R+1\) 个点的简单多边形,包含所有点。满足 \(n \le 2000\),无三点共线。

先求出凸包,然后一个暴力做法就是枚举每一个内部的点,再枚举每一条边和其他的点判断点是否在三角形内即可,复杂度 \(O(n^3)\)

考虑优化,可以枚举点再统计有多少边符合要求,我们以该点为原点进行极角排序,然后如果有凸包上的两点在排序数组中相邻,意味着枚举点到凸包上那条边之间无其他点,该边合法。时间复杂度 \(O(n^2\log n)\)

同样可以枚举边,

image

发现对于某条边,一个点合法当且仅当它们构成的三角形内部无点,考虑用角度刻画,也就是不存在一个点两个角都小于该点,这是一个二维偏序结构,当然不需要二维偏序来解。只需要对于一个角排序,另一个角查看是否为前缀最小值即可。时间复杂度 \(O(n^2\log n)\)

[ZROI 2019]

\(n\) 个点的图,点有点权 \(a_i\),也有点权 $b_i= \sum\limits_{j=1}^i a_j $。且 \(b_n=0\)。现在从 \(1\) 点开始遍历,经过任意点后回到点 \(1\)。从 \(i\) 点到 \(j\) 的收益式子为 \(\frac{a_i-a_i}{2 \times a_i \times a_j} \times b_i \times b_j\)。并且遍历时要求经过点的 \(b\) 权值,在到达某个村庄之前是单调不降的,而之后又是单调不增的。求最大收益,保留五位小数。

我们发现收益式子很神秘,考虑拆开并且把相同下标地放一起,得到

\[w=\frac{1}{2}(\frac{B_j}{A_j}B_i-\frac{B_i}{A_i}B_j) \]

这是一个向量叉乘的结果,考虑平面上的 \(n\) 个点\((B_i,\frac{B_i}{A_i})\),发现只需要维护一个凸包即可找到最优路径。

P10651 [ROI 2017] 虎

闵可夫斯基和

定义对于两个点集 \(A,B\),其闵可夫斯基和为 \(A+B=\{a+b,a\in A,b\in B\}\)

我们研究两个凸包之间的闵可夫斯基和,可以发现是把凸包中的边进行了平移得到的,等价于对于两个凸包中的边进行极角排序之后放在一起。凸包本来就有单调性,所以可以直接归并这些边,复杂度是 \(O(|A|+|B|)\) 的。

具体做法就是初始点是 \(a_0+b_0\),然后我们把凸包中的相邻点作差分(得到了边),按照斜率把种边进行归并加入,每次都在上一个点的基础上加上一个新加入的向量(边)得到一个新的点。注意求完 Minkowski 之后最好再求一次凸包,去掉一次多余的点,比如三点共线之类的。

P4557 [JSOI2018] 战争

本题等价于对于 \(A\)\((-B)\) 求闵可夫斯基和之后,判断给定点是否在凸包之内。

按照上文所述求出凸包之后,我们任意选择一个点作为起点对于凸包进行三角剖分。也就是通过该起点和凸包中任意两个相邻点,把凸包划分为 \(n-2\) 个三角形。然后我们只需要通过叉积判断方向,二分出给定点如果被凸包包含,会在哪个三角形之内,然后再判断是否在这个三角形之内(直接用叉积对于第三条边判定即可)。注意 corner case 就是可能出现某个点恰好处于最后一条边上,特判一下即可。

双倍经验:UVA10256 The Great Divide

P8101 [USACO22JAN] Multiple Choice Test P

很牛的一道题目。

根据 \(x^2\) 的凸性,可能成为答案的向量一定在其所处组的凸包上面。对于多个向量加法,那对应的就是 Minkowski 和了。于是对于每一组向量建立凸包,把对于所有向量进行 Minkowski 和,然后遍历最后的凸包寻找最优答案即可。

如果没有想到第一步凸包怎么办?我们可以从第二步那里反向推回去,没反应出第一步的凸包,但是看到向量的总和我们肯定会想到 Minkowski 和,然而这个时候我们会想到为了尽可能远离起点,所以这个点必须处于“最外面一层”,也就是 Minkowski 和之后的凸包上的点才是有用的点,所以我们需要对于每一组单独建立凸包然后进行 Minkowski 和。

如果快速对于多组向量求解 Minkowski 和?直接一个一个合并复杂度是错的,因为单次的时间复杂度是 \(O(|A|+|B|)\)。一般对于这种复杂度的处理就是你按照 \(|A|\) 的大小从小往大一个一个合并就对了!参考 CF150E Freezing with Style 也是这种处理方法,和启发式合并很像。当然我们也可以分治求。

这里有一种更为高妙的方法,和两个凸包求 Minkowski 和一样,我们只要对于所有凸包中的所有边都放在一起然后极角排序一下放入新的凸包就行了。

QOJ7929.Liquid Distribution

这是一些线性组合的形式,让我们想到了向量。

因此考虑计算几何,饮料混合就是向量加,故考虑 Minkowski 和。

混合饮料的过程就是缩小凸包的过程,

image

于是直接求出原始饮料的闵可夫斯基和,以及目标饮料的闵可夫斯基和。判断是否包含即可。

经典问题

最近点对

KDT/分治/划格子
枚举 \(i \in[1,n]\),设 \(M\) 为目前最近点对的距离。

最小三角形

分治,先把点集按照中位数划分为两部分,然后分别求出两边的最小三角形。设目前最小的是 \(D\),于是沿着中间线向两边分别延长 \(\frac{D}{2}\),枚举每一个点再向下枚举 \(\frac{D}{2}\)。随机情况下 \(\frac{D}{2}\) 的矩形内点的个数为 \(O(1)\)

ABC 234 Ex

划分格子

APIO2018

香港2022

题意:求区间最近点对。
KDT和分治显然不行。于是考虑划格子,第 \(i\) 份格子的边长为 \(2^{i+1}\),于是范围在 \([2^i,2^{i+1})\)

ucup2 Delft B

给定 \(n\) 个点,在边数为 \([3,k]\) 的路径,中最小化 \(\max(d(p_i,p_{i+1}))\),最小化的前提下求 \(k_{min}\),最后再求满足上述两个条件的路径个数。\(k \le30~n\le2\times 10^5\)
先求 \(k=3\) 的时候的答案,设为 \(M\)
注意如果给的是点坐标而非点点近距离,要多从几何角度考虑。

ucup Delft H

给你 \(n\) 个点,有权值,要求找到一个矩形,满足内部点权值和-边长最大。矩形不要求与坐标轴平行。 n 400 8S

V图

概念:给 \(n\) 个点,求出对于每个点,以它为最近点的区域。
求法1:对于每个点求出它与其他点的中垂线,然后再半平面交。
求法2:随机切凸包

凸壳dp技巧

\(n\) 个点,求 \(5\) 个点的凸包的个数。
转化求一个环使得斜率递增。dp 状态枚举起点 \(s\),边 \((i,j)\) ,到的点个数,复杂度太大。可以对于 \(n^2\) 个点求向量,极角排序。枚举向量, \(dp(s,t)\) 表示从 \(s\) 出发只经过枚举过的向量到达 \(t\) 的方案数,对于边 \((u,v)\) ,有 \(dp(s,u) \to dp(s,v)\)

Best Sun

快速点定位

离线从左往右扫描线,维护一下各平面上下顺序。
在线,平衡树树 \(\to\) 可持久化平衡树,\(O(n\log n)\),难写。可以用树套树复杂度 \(O(n\log^2n)\),本质上求每个点最上面一条线是什么。

面积

求多边形面积

  1. 积分
  2. \(\frac{1}{2}\sum(P_i \times P_{i+1})\)

圆交面积

圆交

余弦定理

求解

弓形+多边形/格林公式(微积分)

辛普森积分

\(f(x)\) 表示图形与 \(x=t\) 交线的长度。所以面积为 \(\int f(x)dx\),不好直接积分。可以近似一下。如果 \(f(x)\) 为三次以下多项式就可以近似为 \(\frac{1}{6}(r-l)(f(l)+f(r)+4f(\frac{l+r}{2}))\)

圆上经典问题

圆覆盖点

平面上有 \(n\) 个点,找一个圆覆盖其中 \(k\) 个点,问最小半径。
二分答案 \(R\),以每个点为圆心做一个半径为 \(R\) 的圆,查找是否有区域被覆盖了至少 \(k\) 次,区域查改为查圆弧交的次数。复杂度为 \(O(n^2\log n \log w)\),可以进一步优化。可以对于枚举每个圆单独二分,考虑第 \(i\) 个圆之前的答案,先看看这个圆能否满足,不过不满足就取判断下一个圆,如果满足就说明这个圆可能更新最小答案,那就对前 \(i\) 个圆整体的二分一次。先随机打乱圆,这样每个圆可能更新答案的概率是 \(\frac{1}{i}\),那么这一部分的期望复杂度就是 \(O(\sum\frac{1}{i}*i^2\log n\log w)\)

PKUWC2018

求圆与一个简单多边形交的圆弧长度。

CF1446F Line Distance

经典二分答案,然后判断个数。然后需要以圆点为圆心画一个 \(R\) 的圆。如果在园内和圆上的点显然对其他所有点连线距离满足。园外两点连线需要与圆相切或相交,考虑最极限的情况,

CCPC Guangzhou 2021 L

考虑 \(k_i=1\),判断点是否在凸包内(求每一段直线,用叉积判断点是否在两段直线中间)。二分求切线即可。如果 \(k_i>1\)

CF1019E Raining season

简单多边形点包含

1.在内部/外部,作射线看有奇/偶个交点。
2.在边上,枚举边。

WF2017A

posted @ 2024-02-14 23:24  Mirasycle  阅读(72)  评论(0)    收藏  举报