高维空间的问题
高维空间点集直径
一维直径
在一位空间上的直径是很好求得的,因为我们只要找到所有点中的 \(\min\) 和 \(\max\),就可以 \(O(n)\) 的求得精确解。并且空间复杂度是 \(O(1)\) 的(我们只要存储历史最大值和最小值)。
二维直径
第一种算法是暴力算法,我们可以 \(O(n^2)\) 的枚举点对,然后选出其中最大的距离。这个算法可以在 \(O(n^2)\) 的时间内求得精确解。
第二种算法是近似方法。我们任意选择一个点,然后找到距离它最远的点。假设我们选到的是 \((u,u')\),而真正的直径是 \((v,v')\),那么,连接 \((u,v)\) 和 \((u,v')\),由三角形三边关系得 \((v,v')\le(u,v)+(u,v')\)(可以共线,故可以取等),而又因为 \(u'\) 是离 \(u\) 最远的点,所以 \((u,v)\le (u,u'),(u,v')\le (u,u')\)。则 \((v,v')\le 2(u,u')\)。所以,这个算法可以在 \(O(n)\) 的时间内做到 \(2-\) 近似。
我们可以类比树上直径计算得到第三种算法,两次 \(dfs\),每次找到离当前点最远的点。这样的做法也是 \(O(n)\) 的,但是很遗憾,这依然不是精确解。因为如图中的情况,我们从 \(A\) 开始,找到 \(B\),然后找到 \(BB'\)。但很明显不如 \(AB'\)。树上的情况不能套用到这里来。 不过,这个算法依旧是 \(\sqrt 3-\) 近似的。因为“在相等的两个中任选一个”已经是最极限的情况了。
第四种算法,我们可以先 \(O(n\log n)\) 的算法求出凸包,然后观察到,对于每个点,和它距离最远的点是顺时针单调移动的(这个算法又称旋转卡壳),用双指针维护即可,复杂度 \(O(n)\),不过有求凸包的瓶颈在,所以 \(O(n\log n)\) 是最终的复杂度。
\(d\) 维直径
我们观察二维的几种算法。首先,第一种算法依旧可以给出精确解,但是因为 \(d\) 变成了变量,所以计算距离的复杂度就要算进去,是 \(O(n^2d)\) 的。
第二种也类似,变成 \(O(nd)\) 的 \(2-\) 近似。
第三种也没变,还是 \(\sqrt 3-\) 近似。
唯独在二维中最优的第四种算法,不仅求凸包变成了困难的(仅三维就要 \(n^2\) 的,单调移动的性质更是不复存在了。
那么,既然优秀的做法不复存在,我们就来重新介绍一种线性时间的 \((1+\epsilon)-\) 近似算法。
首先,我们通过算法二估计出直径 \(l\),然后按照 \(\ell=\dfrac{\epsilon l}{\sqrt{d}}\) 将所有的点划分成 \(\ell^d\) 的 hyper cube。接着,我们将所有的点近似到其所在格子的中心,这一步,因为是 \(\ell^d\) 的小方格,所以最多移动 \(\ell\sqrt{d}\)。
然后,我们对所有的小方格暴力求答案,因为直径大约是 \(l\),所以格子一共有 \((\dfrac{\sqrt d}{\epsilon})^d\) 个。
而总的方格数量是 \(16\),所以总的复杂度就是 \(O(\ell^2+n\log d)\) 的。而求出的直径误差不超过 \(2\sqrt d\ell=2\epsilon l\),所以答案是 \((1+\epsilon)-\) 近似的。