在《程序员》第九期算法擂台中看到这个题目,在这儿给出我的解答方案。
题目要求:求出某一点,使所有的骑士到这一点的时间最短;在保证时间最短的情况的下,所有的骑士到这点的路程之和也最短。
解题思路:
1.先求出每个骑士从开始的位置到任意一个位置的所需要的最少的天数,保存在二维数组Days[MAX_Y][MAX_X]中(其中MAX_Y、MAX_X分别为棋盘的行数、列数)。
2.对于每个骑士i (0 <= i < n),都有一个二位数组Daysi[MAX_Y][MAX_X]。创建两个数组MaxDays[MAX_Y][MAX_X]和TotalDays[MAX_Y][MAX_X],使MaxDays[y][x] =Max(Daysi[y][x]),TotalDays[y][x] = ΣDaysi[y][x]。也就是说,二维数组MaxDays的任一个元素的值为所有的骑士对应的Daysi[y][x]的值的最大的一个,而TotalDays的任一个元素TotalDays[y][x]的值为所有骑士的Daysi[y][x]的值的和。(其中0<=y < MAX_Y, 0<= x < MAX_X)。
3.这个时候MaxDays中存放的就是所有骑士到每个位置所需要的时间,而TotalDays中存放的就是所有骑士到每个位置的总共的步数。遍历数组MaxDays,找出最小的值(可能有相同的值),这些最小的值就是需要的最少的时间,这些最小的值的位置就是聚会的位置。然后从TotalDays中找出所有骑士到聚会位置总共走的步数。位置可能不止一个,所以要从这些位置中找出总共的步数的最小值(最小值也可能不止一个)。即过滤掉总共步数不是最小值的位置。
4.最后得到的(x,y)就是我们需要聚会地点,而MaxDays[y][x]就是所需要的天数,TotalDays[y][x]就是所有骑士总共走的步数。
对于2,3,4步,都比较容易,第1步可以通过广度遍历实现:
a) 初始化Daysi[MAX_Y][MAX_X]的所有元素为-1。
b) 假设原始位置为(x0,y0),那么置Days[y0][x0]为0。然后找出从点(x0,y0)所有到达的点(x11,y11)、(x12,y12)…(找到的点可能有0—8个),判断Days[y11][x11]、Days[y12][x12]…是否为-1,如果不为-1,则证明在此日期之前就可以达到,所以不用去管。如果为-1,则置Days[y11][x11]、Days[y12][x12]…为1,依次通过(x11,y11)、(x12,y12)…找出(x21,y21)、(x22,y22)、(x23,y23)……
c) 程序最后结束的条件为所有的点都遍历过,即找到的所有的下一个点都不为-1。
至此,问题已解决。时间复杂度我没有具体地去算,总体来说,程序的运行速度是相当快的。以上是解题的思路,至于编程方面的细节问题,我暂时不写那么详细。
下载可执行文件和源代码:http://zijinshi.cn/prg/knight_20070910.zip。
(完)