8.3 递归与分治
除了排序与检索外,递归还有更广泛的应用。
棋盘覆盖问题。有一个2k*2k的方格棋盘,恰有一个方格是黑色的,其他为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑色方格不能被覆盖,且任意一个白色方格不能同时被两个或更多牌覆盖。如图8-3所示为L型牌的4种旋转方式。
图8-3 L型牌
【分析】
本题的棋盘是2k*2k的,很容易想到分治:把棋盘切为4块,则每一块都是2k-1*2k-1的。有黑格的那一块可以递归解决,但其他3块并没有黑格子,应该怎么办呢?可以构造出一个黑格子,如图8-4所示。递归边界也不难得出:k=1时一块牌就够了。
循环日程表问题。n=2k个运动员进行网球循环赛,需要设计比赛日程表。每个选手必须与其他n-1个选手各赛一次;每个选手一天只能赛一次;循环赛一共进行n-1天。按此要求设计一张比赛日程表,该表有n行和n-1列,第i行j列为第i个选手第j天遇到的选手。
【分析】
本题的方法有很多,递归是其中一种比较容易理解的方法。如图8-5所示是k=3时的一个可行解,它是4块拼起来的。左上角是k=2时的一组解,左下角是左上角每个数加4得到,而右上角、右下角分别由左下角、左上角复制得到。
| ![]() |
| 图8-4 棋盘覆盖问题的递归解法 | 图8-5 循环日程表问题k =3时的解 |
巨人与鬼。在平面上有n个巨人和n个鬼,没有三者在同一条直线上。每个巨人需要选择一个不同的鬼,向其发送质子流消灭它。质子流由巨人发射,沿直线行进,遇到鬼后消失。由于质子流交叉是很危险的,所有质子流经过的线段不能有交点。请设计一种给巨人和鬼配对的方法。
【分析】
由于只需要一种配对方法,从直观上来说本题一定是有解的。由于每一个巨人和鬼都需要找一个目标,不妨先给“最特殊”的巨人或鬼寻找“搭档”。
考虑y坐标最小的点(即最低点)。如果有多个这样的点,考虑最左边的点(即其中最左边的点),则所有点的极角在范围[0,π)内。不妨设它是一个巨人,然后把所有其他点按照极角从小到大的顺序排序后依次检查。
情况1:第一个点是鬼,那么配对完成,剩下的巨人和鬼仍然是一样多,而且不会和这一条线段交叉,如图8-6(a)所示。
情况2:第一个点是巨人,那么继续检查,直到已检查的点中鬼和巨人一样多为止。找到了这个“鬼和巨人”配对区间后,只需要把此区间内的点配对,再把区域外的点配对即可,如图8-6(b)所示。这个配对过程是递归的,好比棋盘覆盖中一样。会不会找不到这样的配对区间呢?不会的。因为检查完第一个点后鬼少一个,而检查完最后一个点时鬼多一个,而巨人和鬼的数量差每次只能改变1,因此“从少到多”的过程中一定会有“一样多”的时候。
| ![]() |
| (a) | (b) |
图8-6 巨人与鬼问题