1. 向量叉乘
定义:
有两向量
A
⃗
(
x
1
,
y
1
)
\vec{A}(x1,y1)
A(x1,y1)和
B
⃗
(
x
2
,
y
2
)
\vec{B}(x2,y2)
B(x2,y2),其叉乘
A
⃗
×
B
⃗
\vec{A}\times\vec{B}
A×B用坐标表示为
x
1
y
2
−
x
2
y
1
x_1y_2-x_2y_1
x1y2−x2y1(顺序不能变);
且因还可以表示为两向量的模长乘以两向量夹角的正弦值
∣
A
⃗
∣
∣
B
⃗
∣
sin
<
A
⃗
,
B
⃗
>
|\vec{A}||\vec{B}|\sin<\vec{A},\vec{B}>
∣A∣∣B∣sin<A,B>(后者应当是由A逆时针旋转至B转过的角度的正弦值)在几何意义上为两向量形成的平行四边形的面积
应用:
由此,可通过叉乘值判断两向量的位置关系:
若 P × Q > 0 , 则P在Q的顺时针方向。
若 P × Q < 0 , 则P在Q的逆时针方向。
若 P × Q = 0 , 则P与Q共线,但可能同向也可能反向。
2. 判断线段相交
-
假设两线段对应两个矢量 A ⃗ \vec{A} A和 B ⃗ \vec{B} B,取A的一端点如A点分别与 B ⃗ \vec{B} B的两端点B和D点连线,两端连线对应的矢量与 A ⃗ \vec{A} A做叉乘运算(保证计算时A的位置始终在同一侧),若两结果异号,则说明 B ⃗ \vec{B} B的两端点在 A ⃗ \vec{A} A的两侧;同理,也可以检测 A ⃗ \vec{A} A的两端点是否在 B ⃗ \vec{B} B的两侧,若两次计算结果都为异号,则两线段相交;
-
若有一次叉乘结果为零另一次为异号,则检测选取的该端点是否在该线段上,具体方法是观察该点坐标是否在另一线段两点围成的平行于坐标轴的矩形内即可。
3. 多边形面积
由于多边形可分为多个小三角形,则可以借助叉乘的几何意义先对三角形面积进行计算,最终加和。
首先对于凸多边形,可以随便取其中一个顶点,连接其他顶点形成对角线,形成‘边数r-2’个三角形然后按照顺时针方向进行叉乘:
S
=
(
P
1
P
2
→
×
P
1
P
3
→
+
P
1
P
3
→
×
P
1
P
4
→
+
P
1
P
4
→
×
P
1
P
5
→
+
P
1
P
5
→
×
P
1
P
6
→
)
/
2
S=(\overrightarrow{P_1P_2}\times\overrightarrow{P_1P_3}+\overrightarrow{P_1P_3}\times\overrightarrow{P_1P_4}+\overrightarrow{P_1P_4}\times\overrightarrow{P_1P_5}+\overrightarrow{P_1P_5}\times\overrightarrow{P_1P_6})/2
S=(P1P2×P1P3+P1P3×P1P4+P1P4×P1P5+P1P5×P1P6)/2(如图)
对于凹多边形该公式仍适用:
S
=
(
P
1
P
2
→
×
P
1
P
3
→
+
P
1
P
3
→
×
P
1
P
4
→
)
/
2
=
S
P
1
P
2
P
3
−
S
P
1
P
3
P
4
S=(\overrightarrow{P_1P_2}\times\overrightarrow{P_1P_3}+\overrightarrow{P_1P_3}\times\overrightarrow{P_1P_4})/2=S_{P_1P_2P_3}-S_{P_1P_3P_4}
S=(P1P2×P1P3+P1P3×P1P4)/2=SP1P2P3−SP1P3P4
更神奇的是,当基准点不再取P1这种顶点而是图形外任意一点时,结论依然成立,只要按照顺时针以一个点为基准遍历一个图形的其余所有顶点做叉乘求和,结果将会等于该图形的面积两倍(易自证)
因此,选取坐标原点为基准点,设图形顶点依次为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . (x_1,y_1),(x_2,y_2),... (x1,y1),(x2,y2),...则图形面积可表示为 S = 1 2 ∑ ∣ x i y i x i + 1 y i + 1 ∣ S=\frac{1}{2}\sum\begin{vmatrix} x_i & y_i \\ x_{i+1} & y_{i+1} \end{vmatrix} S=21∑∣∣∣∣xixi+1yiyi+1∣∣∣∣
4. 凸包(格雷汉姆扫描)
定义:
在平面上能包含所有给定点的最小凸多边形叫做凸包。凸包即为保住所有给定的点所需围成的周长最小的图形。
Graham scan:
对于如何求出凸包上的点,格雷汉姆扫描给出了nlogn的解法。
背景:对于凸包上的点,位于所有点最底部的点一定在凸包上
大致算法:
取纵坐标最小的点P0压入栈中,再以该点为坐标原点对其余所有点按照极角从小到大排序,依次遍历每个点。
将P1压入栈中,计算
P
0
P
1
→
×
P
1
P
2
→
\overrightarrow{P_0P_1}\times\overrightarrow{P_1P_2}
P0P1×P1P2符号,若为负,则将P1弹出栈内,因为此时夹角P0P1P2大于180°,不符合凸多边形的定义。
将P2压入栈中以此类推,每次检验叉乘值时,若始终不符题意,则一直弹栈直至三点夹角在180°以内或栈中只剩一个点。
当重新遍历到P0点时,循环结束,此时栈中存入凸包上的点
算法复杂度:排序算法O(nlogn),压栈弹栈的次数不会超过2n,因为每个点最多只会进出栈共两次,所以总复杂度为O(nlogn)