从零开始的几何学习

本文介绍了计算机几何的基础概念,包括点、向量、线、圆的表示,以及点积和叉积的应用。讨论了如何判断向量位置、线段相交、点与线段的关系等。算法篇涵盖了求凸包、半平面交等方法,以及在实际问题中的应用。此外,还分享了一些编程竞赛中的几何题目级别和解题心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Computational Geometry

概念篇

点/向量:同样使用两个值表示,A向量表示为 A → \overrightarrow{A} A

线/线段:两个点实现,也可以一个点+一个向量实现(方便表示射线)

圆:一个点与一个值分别代表圆形与半径

点积: x 1 x 2 + y 1 y 2 x_1x_2+y_1y_2 x1x2+y1y2 A → ⋅ B → = ∣ A ∣ ⋅ ∣ B ∣ ⋅ c o s Θ \overrightarrow{A}\cdot\overrightarrow{B}=|A|\cdot|B|\cdot cos \Theta A B =ABcosΘ,可以判正交

叉积: x 1 y 2 − x 2 y 1 x_1y_2-x_2y_1 x1y2x2y1,记为 A → × B → \overrightarrow{A}\times\overrightarrow{B} A ×B ,实际上就是由两向量为邻边的平行四边形的面积,有正负之分

半平面:一条直线将平面分成两个部分,其中的一个部分就是半平面。使用一条直线表示,直线的逆时针方向为所选的半平面

思路篇

判定两个向量位置方法: A → × B → \overrightarrow{A}\times\overrightarrow{B} A ×B ,叉积大于0,则 B → \overrightarrow{B} B 位于 A → \overrightarrow{A} A 的逆时针方向。而点积的值可以判定两向量的夹角大小

三角形面积可以由两向量得出,或者利用原点来做,即 O A → × O B → + O B → × O C → + O C → × O A → \overrightarrow{OA}\times\overrightarrow{OB}+\overrightarrow{OB}\times\overrightarrow{OC}+\overrightarrow{OC}\times\overrightarrow{OA} OA ×OB +OB ×OC +OC ×OA ,由于只有三个点,所以只要按照某个方向叉就行了

角度旋转公式: ( x c o s a − y s i n a , x s i n a + y c o s a ) (xcosa-ysina,xsina+ycosa) (xcosaysina,xsina+ycosa),为了避免无斜率,可以提前将所有点旋一点角度

利用点积,叉积来判断两直线关系,叉积判顺时针还是逆时针方向,点积判角度

多边形面积:只要顺时针叉一圈,得到的就是多边形面积的2倍,值得注意的是叉的方向,逆时针是正的,顺时针是负的。其实这就是一个三角剖分

判断两线段是否相交:快速排斥实验,就是将两线段变成两矩形判断是否相交。跨立实验,判断线段的两端是否位于另一个线段两端(利用叉积),判断两次(对每个线段各来一次)即可判断是否存在于严格交。对于非严格交,两次跨立实验无法处理0 0 5 0 6 0 7 0这种情况,所以需要进行两个实验

点到线段:只有了两种情况,一种是点在线段两侧,一种直接点到直线的距离

线段的距离:每个线段端点到另一条线段的距离的最小值,分类讨论后发现极值总是出现在两端

判断是否为凸包:以某一顺序叉一圈,如果每两个向量叉积均为同号或等于0,则为凸包

判断点是否在线段上:当叉积为0时判断是否在之间即可

点与凸包的关系:向某个方向引出一条射线看几个交点,奇数为在之内。由于有直接穿过交点的操作,这种应当算一次,所以可以使用左开右闭。这样也能处理恰好处理射线与凸包上的线重合的问题

凸包的内切圆:将凸包看成一个半平面交,首先二分圆的半径,然后让每个半平面都向有面积的那一侧平移,如果平移后半平面的交依旧不为0,则证明圆的半径能满足。求出半径后,依旧将每个半平面平移,剩下交的面积就是内切圆圆心可在的位置。

pick公式: S = a + b 2 − 1 S=a+\frac{b}{2}-1 S=a+2b1,s是面积,a是内部点数,b是边上点数

double 类型的gcd
double fgcd(double a, double b){
if(b <= eps) return a;
else return fgcd(b, fmod(a, b));
}

算法篇

算凸包:当对点先按x,再按y进行排序后(也可以极角排序),维护一个下凸壳,再维护一个上凸壳。两个凸壳合一起就是一个完整的凸包。维护的过程是利用叉积,因为两边的夹角始终是一个逆时针的,所以可以这么维护。
注意:如果起始点有重点,那么凸包在上下凸壳合并时会出现很多重复点

旋转卡壳:假如要算凸包直径,可以枚举点,同时枚举另一个点,由于其他点到当前点的距离是一个单峰函数,所以可以直接枚举。同时能够发现,这个过程是具有传递性的。当然,旋转卡壳能算的东西很多,矩阵覆盖什么的都是能算的

半平面交: 首先,半平面交的过程非常类似于形成一个凸包的过程,并且最后形成的图形也是一个凸包,那么就可以类似于凸包那样的去求。首先排个序,用一个队列记录目前已有的半平面选择的交点中,相邻两条直线的焦点,那么如果上一个交点在当前直线的右侧,就证明当前直线能完美替代上一条直线。这样的更新非常类似于凸包。
不过还有一种情况,就是新加入的线段会淘汰掉一开始加入的线段(因为维护的是一个凸包的形式,所以转一圈回去后,还能淘汰一开始的直线),那么这样也需要判断。
由于一开始加进去的线具有更高的优先程度,所以先删队尾再删队头

圆的反演

闵可夫斯基和
给你两个点集 A , B A,B A,B,定义他们的闵可夫斯基和为C,C满足 c = { a + b ∣ a ∈ A , b ∈ B } c=\left\{a+b|a{\in}A,b{\in}B\right\} c={a+baA,bB}
如果我们要求C的凸包,能够发现,C凸包上的点一定是由A,B凸包上的点得来的

玄学时间

用int存整数会wa,用double存ac

半平面交的时候,强行加个框就AC了

POJ的G++要使用.f输出,C++使用.lf输出

结果可以加个eps(防止出现-0.0这种情况)

写过的题目:

1级(板子或者随便写写即可)
2级(有了一定的难度)

HDU - 3272讨论的技巧

3级(和其他算法结合或推导过程难度较大)
4级(看到就很头大)

写着写着就忘记写博客了,所以先咕咕了,哪天有想法了再补全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值