【模板】最小圆覆盖

三点定圆

已知三个不在同一直线上的点 \((x_1, y_1), (x_2, y_2), (x_3, y_3)\)。请确定过此三点的圆的圆心。

设圆心为 \((x, y)\),半径为 \(r\),则圆的方程为

\[(x_i-x)^2+(y_i-y)^2=r^2 \]

展开得到

\[x_i^2-2x_ix+x^2+y_i^2-2y_iy+y^2=r^2 \]

我们并不需要现在得知 \(r\) 的具体值,即我们并不关心 \(r^2\)。不妨把未知数的平方项合并为一个常数 \(C\)

\[2x_ix+2y_iy+C=x_i^2+y_i^2 \]

即我们现在需要求这个方程组的解:

\[\begin{bmatrix} x_1& y_1& 1\\ x_2& y_2& 1\\ x_3& y_3& 1\\ \end{bmatrix}\times \begin{bmatrix} 2x\\ 2y\\ C\\ \end{bmatrix}= \begin{bmatrix} x_1^2+y_1^2\\ x_2^2+y_2^2\\ x_3^2+y_3^2\\ \end{bmatrix} \]

根据克莱默法则,我们只需要求三个三阶行列式。

考虑到这三个行列式的最右边都是一列 \(1\),不妨将行列式沿着 \(1\) 展开,如:

\[\begin{vmatrix} x_1& y_1& 1\\ x_2& y_2& 1\\ x_3& y_3& 1\\ \end{vmatrix}= \begin{vmatrix} x_2& y_2\\ x_3& y_3\\ \end{vmatrix}- \begin{vmatrix} x_1& y_1\\ x_3& y_3\\ \end{vmatrix}+ \begin{vmatrix} x_1& y_1\\ x_2& y_2\\ \end{vmatrix} \]

也就稍微好写一点点。

最小圆覆盖

先看算法流程:

shuffle(a + 1, a + n + 1, mt19937{random_device{}()});
dot O = a[1];
double r = 0;
for (int i = 2; i <= n; i++) {
  if (dis(a[i], O) - r < eps) continue; // 在圆内
  O = a[i], r = 0;
  for (int j = 1; j < i; j++) {
    if (dis(a[j], O) - r < eps) continue;
    O = (a[i] + a[j]) / 2, r = dis(a[i], a[j]) / 2;
    for (int k = 1; k < j; k++) {
      if (dis(a[k], O) - r < eps) continue;
      O = minCircle(a[i], a[j], a[k]), r = dis(O, a[i]);
    }
  }
}

注意枚举顺序,\(i, j, k\) 都是从小往大枚举。

正确性证明

https://www.luogu.com.cn/article/8imn9rtw 不想抄了。这里补充最后一步的依据,是这个引理。

存在 \(𝑁,𝑀∈{𝐼,𝐽,𝐾}\)\(𝑁≠𝑀\),使得 \(circle⁡({𝑁,𝑀,𝑃})\) 包含这四个点。

因为另外几组点都说不可能了,那么一定是剩下这一组了。

时间复杂度证明

根据引理

对于一个 \(n\) 个点随机的序列,因为三点定一个圆,所以每一个点有 \(3/n\) 的概率成为更新这些点的最小圆覆盖的点(点会出现在新的圆上)。

可以发现,对于固定的 \(i,j\)\(j\) 更新了最小圆,时间复杂度为 \(O(j)\);撤去 \(j\) 的固定,发现只有 \(O(i\times 3/i)=O(1)\)\(j\) 会触发时间复杂度 \(O(j)\) 的循环,所以固定 \(i\)\(i\) 更新了最小圆的时间复杂度为 \(O(i)\);撤去 \(i\) 个贡献同理,只有 \(O(n\times 3/n)=O(1)\)\(i\) 会更新最小圆,故总的时间复杂度为 \(O(n)\)

posted @ 2024-07-25 09:18  caijianhong  阅读(6)  评论(0编辑  收藏  举报