1.悬线法的用途
针对求给定矩阵中满足某条件的极大矩阵,比如“面积最大的长方形、正方形”“周长最长的矩形等等”。可以满足在时间复杂度为O(M*N)的要求,比一般的枚举高效的多,也易于理解。
2.悬线法思路
悬线法,悬线的定义,就是一条竖线,这条竖线要满足上端点在整个矩形上边界或者是一个障碍点。然后以这条悬线进行左右移动,直到移至障碍点或者是矩阵边界,进而确定这条悬线所在的极大矩阵。也就是说,我们要针对矩阵中每个点进行求极大矩阵的操作,所以我们需要Left[]数组存每个点能到达的最右位置,Right[]数组存放每个点能到达的最左位置,Up[]数组位置。设置好这些数组之后,我们开始遍历矩阵中的每个点ves[i,j],把每个点和上一个点(ves[i-1][j])的Left和Right进行比较,分别取最大和最小,Up则是上一个点的Up+1,进而求出面积进行比较。所以我们可以得到相关的递推公式。
递推公式:Up:Up[i][j] = Up[i-1][j] + 1
Right:min(Right[i][j],RIght[i-1],[j])
Left::max(Left[i][j],Left[i-1][j])
在这里推荐一篇国家队的论文《极大化思想解决最大子矩阵问题》这里全面讲解了极大化矩阵的思想,只要能看透,我相信对于悬线法的理解肯定会更加深入。只是没有例题,所以你进行理解后再倒回来理解我的例题,印象会更加深刻。
3. 问题引入
最大子矩形问题:在一个给定的矩形网格中有一些障碍点,要找出网格内部不包含任何障碍点,且边界与坐标轴平行的最大子矩形。
这是近期经常出现的问题,例如冬令营2002的《奶牛浴场》,就属于最大子矩形问题。
Winter Camp2002,奶牛浴场
题意简述:(原题见论文附件)
John要在矩形牛场中建造一个大型浴场,但是这个大型浴场不能包含任何一个奶牛的产奶点,但产奶点可以出在浴场的边界上。John的牛场和规划的浴场都是矩形,浴场要完全位于牛场之内,并且浴场的轮廓要与牛场的轮廓平行或者重合。要求所求浴场的面积尽可能大。
参数约定:产奶点的个数S不超过5000,牛场的范围N×M不超过30000×30000。
一、 定义和说明
首先明确一些概念。
1、定义有效子矩形为内部不包含任何障碍点且边界与坐标轴平行的子矩形。如图所示,第一个是有效子矩形(尽管边界上有障碍点),第二个不是有效子矩形(因为内部含有障碍点)。
2、极大有效子矩形:一个有效子矩形,如果不存在包含它且比它大的有效子矩形,就称这个有效子矩形为极大有效子矩形。(为了叙述方便,以下称为极大子矩形)
3、定义最大有效子矩形为所有有效子矩形中最大的一个(或多个)。以下简称为最大子矩形。
二、 极大化思想
【定理1】在一个有障碍点的矩形中的最大子矩形一定是一个极大子矩形。
证明:如果最大子矩形A不是一个极大子矩形,那么根据极大子矩形的定义,存在一个包含A且比A更大的有效子矩形,这与“A是最大子矩形”矛盾,所以【定理1】成立。
三、从问题的特征入手,得到两种常用的算法
定理1虽然很显然,但却是很重要的。根据定理1,我们可以得到这样一个解题思路:
通过枚举所有的极大子矩形,就可以找到最大子矩形。下面根据这个思路来设计算法。
约定:为了叙述方便,设整个矩形的大小为n×m,其中障碍点个数为s。
算法1
算法的思路是通过枚举所有的极大子矩形找出最大子矩形。根据这个思路可以发现,如果算法中有一次枚举的子矩形不是有效子矩形、或者不是极大子矩形,那么可以肯定这个算法做了“无用功”,这也就是需要优化的地方。怎样保证每次枚举的都是极大子矩形呢,我们先从极大子矩形的特征入手。
【定理2】:一个极大子矩形的四条边一定都不能向外扩展。更进一步地说,一个有效子矩形是极大子矩形的充要条件是这个子矩形的每条边要么覆盖了一个障碍点,要么与整个矩形的边界重合。
定理2的正确性很显然,如果一个有效子矩形的某一条边既没有覆盖一个障碍点,又没有与整个矩形的边界重合
,那么肯定存在一个包含它的有效子矩形。根据定理2,我们可以得到一个枚举极大子矩形的算法。为了处理方便,首先在障碍点的集合中加上整个矩形四角上的点。每次枚举子矩形的上下左右边界(枚举覆盖的障碍点),然后判断是否合法(内部是否有包含障碍点)。这样的算法时间复杂度为O(S5),显然太高了。考虑到极大子矩形不能包含障碍点,因此这样枚举4个边界显然会产生大量的无效子矩形。
考虑只枚举左右边界的情况。对于已经确定的左右边界,可以将所有处在这个边界内的点按从上到下排序,如图1中所示,每一格就代表一个有效子矩形。这样做时间复杂度为O(S3)。由于确保每次得到的矩形都是合法的,所以枚举量比前一种算法小了很多。但需要注意的是,这样做枚举的子矩形虽然是合法的,然而不一定是极大
的。所以这个算法还有优化的余地。通过对