最小圆覆盖
最小圆覆盖问题,研究的是对于平面中 N N N 个点,求出覆盖所有点的最小圆问题,圆的边界被认为在圆的内部。且该问题经常被推广到 n n n 维空间中,(最小(超)球覆盖)。本文记录一种常见算法:随机增量算法。
随机增量算法基于以下三个事实:
- 对于点集 S S S ,最小覆盖圆是唯一的。
- 对于点 P P P 与点集 S S S, 如果点 P P P 不在 S S S 的最小覆盖圆内部,则点 P P P 一定在点集 P ∪ S P \cup S P∪S 的最小覆盖圆的边界上。
- 三点可以确定一个圆。
证明:不会
算法流程
-
将要求解的点集重新随机排列
-
选取第一个点,对最小覆盖圆进行初始化,圆心为初始点,半径为0,然后按顺序尝试加入剩下的所有顶点。更新答案。
-
如果一个顶点 i i i被包含在此时的最小覆盖圆中,则不必更新。否则根据性质可知这个点一定在新的最小覆盖圆的边界上,转到 4 来进一步确定前 i i i个点的最小覆盖圆。
-
由于已经知道点 i i i 在新圆的边界上,所以将最小覆盖圆重新设为以点 i i i 为圆心,半径为0的圆,并将前 i − 1 i-1 i−1 个点重新加入进来。
-
令点 j j j 为 i i i 之前的某点。 若点 j j j 包含在此时的最小覆盖圆中,则不需要更新,否则将最小覆盖圆更新为,以 线段 i j ij ij为直径的圆,理由是点 j j j 也是新圆边界上的一点,此时以 i j ij ij 为直径显然比以 i j ij ij 为弦更优。然后再把点 j j j 之前的所有点重新加入进来。
-
令点 k k k 为 点 j j j 之前的某点,说明点 k k k 也一定在前 k k k 个点最小覆盖圆的边界上,且由于三点能确定一个圆,所以不会出现更新后的圆把 k k k 之前的点排除在外的可能性了。此时用以 i i i, j j j, k k k 为顶点的三角形的外接圆更新最小覆盖圆即可。
这里要说一下:第一步随机排列很玄学,它是该算法时间复杂度的保证,据说:对于随机排列的点集,该算法的时间复杂度期望值为线性,但如果点并非随机排列则不能保证,证明这件事,似乎利用了比较高深的数学知识,反正网上的证明,不是感觉离谱,就是看不懂。
这个算法的实际表现也确实和线性复杂度无异。
伪代码:
圆 C;
for(i=1 to n)
{
if(P[i] 不在 C 内)
{
C = {P[i], 0};
for(j=1 to i-1)
{
if(P[j] 不在 C 内)
{
C = {0.5*(P[i]+P[j]), 0.5*dist(P[i], P[j])};
for(k=1 to j-1)
{
if(P[k] 不在 C 内)
{
C = 外接圆(P[i], P[j], P[k]);
}
}
}
}
}
}
例题
模板: 洛谷P1742 最小圆覆盖.