问题描述:
Suppose now that you're given an n × n grid graph $G$. (An n × n graph is just the adjacency graph of an $n \times n$ chessboard. To be completely precise, it is a graph whose node set is the set of all ordered pairs of natural numbers $(i,j)$, where 1 <= i <=n and 1 <= j <= n; the nodes $(i,j)$ and $(k,l)$ are joined by an edge if and only if $|i-k|+|j-l|=1$.)
Each node v is labeled by a real number xv you may assume that all these labels are distinct.
Show how to find a local minimum of G using only O(n) probes to the nodes of $G$. (Note that G has n^2 nodes.)
解题思路:
首先拿到这样的题,由于是要在O(n)的时间内得到解,暴力枚举的方法显然是行不通的。那么怎样才能找到分治的出路,使得问题的规模减小,并且得到的子问题的数目是可数个,最重要的是子问题的性质应当与原问题一样。
在一个 n × n 的图中寻找局部最小值点,初始的考察范围应当是整个 n × n 总共n^2个格子,那么我们只需要逐步地缩小考察的范围,并且保证我们每一步考察的子范围是一定包含局部最小值的。
鉴于此,可从如下几个方面来解决这个问题:
为方便描述,假设该图G是在二维平面上的x = 1, x=2 ,..., x=n 和 y = 1, y =2, y = n 这2n 条直线的交点形成的
1 首先比较图中红色的直线相交形成的4*n个点,得到一个对应值x最小的点x_min, 这样的x_min共有三种情况,如图中的
A1 4个 n/2 * n/2 共享这个节点
A2 2个 n/2 * n/2 共享这个节点
A3 1个 n/2 * n/2 共享这个节点
针对上述3种情况,显然 如果是 A3,我们只需考虑左上角的 n/2 * n/2 子方块
如果是 A2 或者是 A1 我们应该做何选择,已保证该子模块一定能够得到一个局部极小值点呢。接下来我们以 A1 为例(A2只是A1的一个特例)
2 对于A1,我们首先需要确定A1是否是我们的局部极小值点,比较A1和它的4个邻居,如果A1是最小的,那么A1即为所求。
如果不是A1,则选择A1的一个“小于A1“ 的邻居节点,(不是一般性,直接选最小的)。假设这个最小点是B,那么我们将问题缩小到了右上角区域或者是右下角区域;
3 再考察B的上下2个邻居(因为在第一步B的右邻居就已经大于A1,被排除了(因为A1是最小的)),如果B最小,输出B;
否则,选择B的最小的那个邻居,然后决定一个区域,不是一般性,我们假设是右上区域,这样我们就将问题缩小到了 n/2 * n/2 这样的一个区域。问题规模直接减半。
4 只需要递归的进行1,2,3步,即可得到一个局部极小值点。
复杂度分析:
第1步的时间复杂度是O(n), 我们只需要找到最小值即可。
第2步的时间复杂度是常数,因为A1与它的至多4个邻居做比较。(至多的意思是,每个点至多比较4次)
第3步的时间复杂度是常熟,因为A1与它的至多2个邻居比较。 (因为每次考察到B点时,它的邻居已经至少被排除两个)
则将问题降到 n/2 * n/2 的规模时,耗费的时间是O(n),因此有
T(n) = T (n/2) + O(n)
根据主定理,可以有T(n) = O(n)
正确性的证明:
显然在整个过程中,我们每一次考察的点都是一个递减的序列,因此我们最后考察的数一定是局部极小的。
PS:在算法的第一步其实可以只选取 x=n/2 和 y=n/2两条直线的的2n个点,同样可以得到正确答案。
问题反思:此题是一个很好的将问题在O(n)的时间内将问题的规模缩小一半,因此只需要O(n)就可以将问题缩小到常数规模;
在多数要求将问题在O(n)的时间内解决的分治的问题,我们能做的就是将问题在O(n)的时间内将问题的考察规模缩小,进而实现分治,其实一般只考虑某一个一定包含解的子问题即可。
修正:其实每次我只需要比较4条红色的线形成的9个顶点(感谢Tony549285469帮我指出错误),那么情况就会分为类似上面的3种。