《程序员》 -- 计算几何的魅力:美术馆问题

自己非常喜欢《程序员》杂志,《程序员》杂志在一定程序上很能开阔我们的视野。因此,一直都想推荐给大家。

方便大家相互学习交流,本文转自《程序员》杂志

http://www.csdn.net/article/2013-08-20/2816644

————————————————————————————————————————————————————————————————————————————

美术馆问题 

假如有一个凹四边形的美术馆。我们需要在美术馆当中安排尽可能少的警卫,使得他们能观察到美术馆的所有角落。我们可以像图1那样安排两个警卫,但实际上,像图2那样安排一个警卫就够了。如果美术馆的形状更加复杂,很可能一个警卫永远不够,例如在图3所示的美术馆中,安排两个警卫是必需的。如果美术馆的形状更加复杂,例如图4那样,那么最少需要安排多少个警卫呢?这就是著名的美术馆问题(Art Gallery Problem):给定一个多边形,确定最少需要在多边形内放置多少名警卫,才能让他们的视野覆盖整个多边形。 
《程序员》 -- 计算几何的魅力:美术馆问题_第1张图片
有时,虽然多边形非常复杂,顶点数非常多,但放置一个警卫就够了(如图5所示)。当然,也有一些构造多边形的定式,可以充分利用顶点的数目,产生尽可能多的偏僻角落,从而增加所需警卫的数目。例如,利用图6所示的方法便能得出一系列含有n=3k个顶点的多边形,使得里面至少要放置k个警卫才行。如果顶点数是3k+1或者3k+2的话,我们可以先作出顶点数为3k的多边形,再把剩下的顶点当作“废”的顶点添加进去,这仍然可以让所需警卫的数量达到k。由此可知,对于任意顶点数n,我们都能找到一个至少需要⌊n/3」个警卫的多边形(其中⌊x⌋表示不超过x的最大整数)。

1975年,Václav Chvátal证明了一个非常经典的结论:对于任意一个含有n个顶点的多边形,放置⌊n/3⌋个警卫永远是足够的。不过,Václav Chvátal给出的证明过程非常复杂。1978年,Steve Fisk给出了另一种非常精妙的证明,整个证明过程只有五行。
《程序员》 -- 计算几何的魅力:美术馆问题_第2张图片
让我们先来看看Fisk的证明思想。多边形中的视野问题不好处理,但三角形中的视野问题是很简单的:站在其中的任意一个位置都能观察到这个三角形中的每一个点(究其原因,是因为三角形永远是一个凸图形)。我们可以作出多边形的若干条对角线,把整个多边形划分成一个个的三角形,如图7所示。在每一个三角形里面放一个警卫,就能看守整个多边形了。不过,把警卫放在每个三角形的正中间也实在是有些亏。为什么不把警卫放在多边形的对角线上呢?多边形的每一条对角线都是两个三角形的公共边,站在它上面的每一个警卫都能同时看守两个三角形。这样一来,我们便能大大减少所需警卫的数目。其实,把警卫放在边上还是很亏。为什么不把警卫放在多边形的顶点上呢?这样的话,每个警卫都能看遍顶点交汇于此的所有三角形了。这就是Fisk的证明思路。

把任意一个顶点数为n的多边形分割成小三角形。将各顶点染成红、绿、蓝三种颜色,使得每一个三角形的三个顶点正好是三种不同的颜色(如图8)。不妨假设,在三种颜色的顶点中,红色的顶点最少。那么,红色顶点的数目一定小于等于n/3。现在,在每个红色顶点处各安排一名警卫。由于每个三角形都有一个红色的顶点,所以每个三角形里的每一个点都保证能被看到。这样,我们就找到了一个大小不超过⌊n/3⌋的点集,它们足以看到多边形内的每一个点。

Fisk给出的证明非常巧妙,不过里面略去了很多细节问题。为什么存在满足要求的染色方案?更进一步地问,为什么我们可以把多边形分割成一个个的小三角形?这其实都是需要证明的。
《程序员》 -- 计算几何的魅力:美术馆问题_第3张图片

多边形的三角剖分

大家或许会说,一个多边形能被分割成若干个小三角形,这不是一件很显然的事情吗?比方说,随便找一条把多边形分成两部分的对角线,然后递归地对每一部分进行分割,直到最终变成了一堆三角形为止。这个推理过程看上去很合理,但却有一个不易察觉的漏洞:你怎么敢肯定,存在一条把多边形分成两部分的对角线呢?令人吃惊的是,证明这一点并不容易。

1975年,Meisters给出了一个证明。首先,选取一个横坐标最小的顶点。由于其他点都位于这个点的右侧(最多和它在同一竖直线上),因此这一定是一个向外凸的点。不妨把这个点记作Pi,把与它相邻的两个点记作Pi-1和Pi+1。如果Pi-1和Pi+1的连线与多边形的每一条边都不相交,这说明Pi-1Pi+1完全在多边形的内部,它就是一条把多边形分成两块的对角线,如图9所示。如果Pi-1和Pi+1的连线穿过了至少一条多边形的边,这就说明Pi-1Pi+1有一部分跑到了多边形外面去了,它不是一条可取的对角线。那该怎么办呢?容易看出,三角形PiPi-1Pi+1里面一定会包含其他的顶点。我们从中选择一个距离直线Pi-1Pi+1最远的点,不妨把它记作R,如图10所示。那么,过R作Pi-1Pi+1的平行线,其左侧就不会再有别的点了。于是,PiR就是一条安全的连线,它将会把多边形分成两部分。

顺时针(或者逆时针)给出多边形各个顶点的坐标,我们可以用O(n)的时间找出一条把多边形分成两部分的对角线。找出最左边的那个顶点Pi需要O(n)的时间,判断Pi-1Pi+1是否与多边形各边发生相交也需要O(n)的时间。如果确实有相交的情况发生,那么我们就枚举除了Pi、Pi-1、Pi+1之外的每一个顶点,筛选出位于三角形Pi、Pi-1、Pi+1以内的点,并找出其中哪个点和Pi-1、Pi+1所构成的三角形面积最大。根据三角形的面积公式,这个点就一定是到Pi-1、Pi+1距离最远的点了。这都可以在O(n)的时间里完成。

之后,整个多边形将会被分成两个小多边形,每个小多边形的顶点数都比原多边形更少一些。如果其中一个小多边形有k个顶点(注意到k一定是大于等于3的),那么另一个小多边形将会有n-k+2个顶点(因为这两个小多边形会有两个公共顶点),但考虑到k≥3,后一个多边形的顶点数仍然是一个比n小的数。递归地对两个小多边形进行细分,便能得到最终的三角剖分方案了。我们可以用数学归纳法来证明,整个多边形最终将会被n–3条对角线分成n–2个小三角形。根据归纳假设,其中一个小多边形将会被k–3条对角线分成k–2个小三角形,另一个小多边形则会被n-k–1条对角线分成n-k个小三角形。把两个小多边形合在一起,于是就有(k–3)+(n-k–1)+1=n–3条对角线(注意到两个小多边形的粘合处也是大多边形的一条对角线),以及(k–2)+(n-k)=n–2个小三角形。

因此,在递归地把各个小多边形都分到底的过程中,我们总共会找出O(n)条对角线,每次找到一条对角线都需要花费O(n)的时间,因而总的复杂度就是O(n²)。当然,考虑到后面需要处理的多边形越来越小,因而实际的时间复杂度可能会更低。运气最好时,每条对角线都把多边形分成了顶点数相等的两个小多边形,则总的复杂度就是O(n·log n)。

1977年,Lee和Preparata提出了一种利用“单调多边形”进行快速三角剖分的方法,在最坏情况下的复杂度也是O(n·log n)。之后的很长一段时间里,人们都在思考这样一个问题:是否存在复杂度低于O(n·log n)的三角形剖分算法。1988年,Tarjan和Van Wyk提出了一种O(n·log log n)的算法,从而给出了一个肯定的回答。1991年,Bernard Chazelle用将近40页的篇幅描述了一种O(n)的算法,虽然算法本身极其复杂,但为三角形剖分的复杂度问题画上了一个句号。
《程序员》 -- 计算几何的魅力:美术馆问题_第4张图片
《程序员》 -- 计算几何的魅力:美术馆问题_第5张图片

形形色色的变形问题

接下来,大家可以自己尝试着把图7中的各个顶点染成三种颜色,使得相邻顶点的颜色都不相同。稍作尝试,你会发现这并不困难。随便选择一个三角形,把它的三个顶点染成三种不同的颜色,然后像玩扫雷游戏一样顺推下去,得出其他所有点的颜色。每一次,我们总是从一个已染好颜色的三角形出发,迈过一条对角线,来到一个新的三角形里。在这个新的三角形中,只有一个顶点还没有颜色,我们只需要给它染上与其他两个顶点都不同的颜色即可。这样,我们就用掉了一条对角线,处理了一个新的三角形,给一个新的顶点染上了颜色。刚开始,我们没有跨过任何对角线,手中只有一个处理过的三角形,只有三个顶点被染了颜色。等到所有n–3条对角线都用掉了之后,所有n–2个三角形也就全部处理完了,所有n个顶点也就都有颜色了。整个过程相当于一次深度优先搜索,时间复杂度为O(n)。

最后,看看哪种颜色的顶点最少,那么就把警卫安放在这种颜色的顶点上。因而,我们不但成功地证明了⌊n/3⌋个警卫的充分性,还给出了一种安放这⌊n/3⌋个警卫的算法来。

有趣的是,如果多边形里面有“洞”(比方说房间里的立柱),如图11所示,此时三角剖分的算法和染色环节的算法都会失效。在三角剖分时,我们总是假设每条对角线都能把多边形分成两块,然而对于有洞的多边形来说,这一点并不总是成立的。我们之所以能顺利地完成染色环节,也是因为多边形里面没有洞。在一个正常的多边形中,每一条对角线都会把整个多边形断成两部分,因此绝不会出现从某处出发连续跨过若干条对角线最后又回到出发点的情况;但在一个有洞的多边形中,我们有可能走着走着就回到了已处理过的地方,新三角形的第三个顶点有可能已被染过色了,进而导致矛盾产生。

不过,我们可以把一个有洞的多边形看作是一个普通的多边形。假如一个多边形里面有h个洞,那么我们就可以像图12那样,在图中增加2h个顶点,把这h个洞都和外面连通,使得整个图变成拥有n+2h个顶点的多边形。我们立即证明了,一个顶点数为n的、含有h个洞的多边形一定能被⌊(n+2h)/3⌋个警卫完全看守住。

另一方面,人们已找到了一系列的多边形,它们都需要至少⌊(n+h)/3⌋名警卫才能被完全看住。但人们怎么也找不到所需警卫更多的多边形了。于是,人们猜想,⌊(n+h)/3⌋个警卫是否也一定足够了呢?1986年,Shermer成功证明了h=1的情形,但这种证明方法很难推广到h>1的情形。1991年,Hoffmann、Kaufmann和Kriegel终于证明了h>1的情形,从而完美地解决了允许中间有洞的美术馆问题。

除了给多边形挖洞以外,人们还研究了很多美术馆问题的变形。1983年,O'Rourke证明了,如果允许每一名警卫都沿着一条线段来回移动,那么⌊n/4⌋名警卫一定是足够的。1984年,Kahn、Klawe和Kleitman证明了,如果多边形的每条边都是水平的或者竖直的,那么⌊n/4⌋名警卫一定是足够的。2003年,Michael和Pinciu证明了,如果要求每个警卫都能被至少一个别的警卫看到,那么⌊(3n-1)/7⌋名警卫一定是足够的。并且,我们总能构造一些特殊的多边形,让所需的警卫数达到刚才这些上界。这说明,上面这些结论都已不能再改进了。

不过,这些结论都只提供了所需警卫的上界。对于一些特定的多边形来说,我们远远用不到这么多警卫,就像图5那样。给出一个特定的多边形后,如何求出最少所需的警卫数目?1986年,D. Lee和A. Lin证明了,这个问题是NP-hard的。这是计算几何中一个非常重要的结论。

还有很多与线路规划相关的问题也是NP-hard的,例如著名的旅行商问题(Travelling Salesman Problem):给出平面上的若干个点,求出经过每个点恰好一次并且回到出发点的最短路线。不可思议的是,如果把美术馆问题和旅行商问题“杂交”一下,得出的问题竟然是有多项式解法的。1988年,Chin和Ntafos提出了这么一个问题:给定一个多边形,如何找出多边形内的一条最短回路,使得途中能看到多边形里面的每一个点?1995年,Nilsson给出了一个O(n6)的算法,从而证明了上述问题能在多项式的时间内解决。

此外,Chin和Ntafos还考虑了这样一个问题:给定一个多边形,以及多边形边界上的一点(相当于美术馆的大门),如何找出一条从该点出发,最后又回到该点的路线,使得途中能够看到多边形里面的每一个点?两人在1991年给出了一个O(n4)的算法。1997年,Carlsson、Jonsson和Nilsson指出了这个算法中的一处漏洞,并提出了一种修正的方案。然而,两年之后,Tan、Hirata和Inagaki发现,这个修正方案本身也是有问题的。在同一篇论文中,他们给出了一种O(n4)的算法,目前看来应该是正确的。

人们提出这些问题,固然是因为有其实际应用价值——安装最少的摄像头来监视超市里的每个角落,使用为数不多的点光源照亮整个房间,布置数量有限的激光扫描器来生成室内三维地图,设计最优的摄像机轨道铺设方案,让机器人自动寻找最佳的进楼搜救路线等。然而更关键的则是这些问题本身的吸引力。美术馆问题本身拥有极其简单的描述和极其直观的解释,解决起来则需要综合应用几何、图论和计算机科学等诸多领域中的知识和技巧。这无疑是计算几何中最具魅力的问题之一。

作者顾森,网名Matrix67,数学爱好者。2005年开办数学博客http://www.matrix67.com,至今已积累上千篇文章,有上万人订阅。新书《思考的乐趣》已在图灵公司出版。


你可能感兴趣的:(程序员,计算机科学,程序员杂志)