01
A
什么是凸包?
NailslnTheTable
PaintBlending
ColorSpace
ConvexHull:所有分量总和为100%且非负。
B
Extremity(极性)
极点(Extreme Point):在一组点中,沿着这个点座直线,必然能找到一条直线,使得其他所有点都在该直线的一侧。
Strategy
将问题转化为如何在所有点中鉴别极点和非极点。
判断一个点是否会被包含于另外三个点所确定的三角形内部。如果是则不是极点。
In-Triangle Test
伪代码:
Mark all points of S as EXTREME
for each triangle \(\Delta (p, q, r)\)
for each \(s\in S\\ \{p, q, r\}\)
If \(s \in \Delta(p, q, r)\) then
mark s as NON_EXTREME
void extremePoint(Point S[], int n)
{
for(int s = 0; s < n; s++) S[s].extreme = true;
for(int p = 0; p < n; p++)
for(int q = p + 1; q < n; q++)
for(int r = q + 1; r < n; r++)
for(int s = 0; s < n; s++)
{
if(s == p || s == q || s == r || !S[s].extreme)
continue;
if(InTriangle(S[p], S[q], S[r], S[s]))
S[s].extreme = false;
}
}
复杂度为\(O(n^4)\)。
To-Left Test
如何判定点是否落在三角形内部?
点相对于另外两个点确定的有向线段而言落在左侧还是右侧?
InTriangle(p, q, r, s) iff
ToLeft(p, q, s) == ToLeft(q, r, s) == ToLeft(r, p, s) == True
Determinal
利用海伦公式求有向面积,基于行列式进行ToLeft测试。
bool ToLeft(Point p, Point q, Point s)
{
return Area2(p, q, s) > 0;
}
int Area2(Point p, Point q, Point s)
{
return p.x * q.y -p.y * q.x
+ q.x + s.y - q.y * s.x
+s.x * p.y -s.y * p.x;
}
有效地把运算限制在整数域,避免浮点运算的误差。
C
Definition
Extreme Edge(极边):对凸包有贡献的边。
问题转化为如何甄别任意两点之间连边是否为极边。
Algorithm
伪代码:
For each directed segment pq
If points in S{p, q} lie to the same side of pq then
Let EE = EE \(\cup\) {pq}
复杂度为\(O(n^3)\)。
void markEE(Point S[], int n)
{
for(int k = 0; k < n; k++)
{
S[k].extreme = False;
}
for(int p = 0; p < n; p++)
{
for(int q = p + 1; q < n; q++)
{
checkEdge(S, n, p, q);//有向边pq
}
}
}
void checkEdge(Point S[], int n, int p, int q)
{
bool LEmpty = True, REmpty = True;
for(int l = 0; k < n && (LEmpty || REmpty); k++)
{
if(k != p && k != q)//非端点
{
ToLeft(S[p], S[q], S[k]) ? LEmpty = False : REmpty = False;
}
if(LEmpty || REmpty)
{
S[p].extreme = S[q].extreme = True;
}
}
}