1.课题 给定一个列数为M,行数为N的方格棋盘。 棋盘上定义起点、终点、道路、墙壁。 棋盘上必有一个起点和一个终点,剩余方格必定为道路或者墙壁。 现寻求角色从起点到终点的最短路径长度,其中角色只能上下左右移动。
 
 
2.输入与输出 棋盘信息由文本文件提供。 第一行为列数M与行数N,由空格隔开。 第二行以后的N行,各为由空格隔开的M个字符。 其中,“s”代表起点,“g”代表终点,“0”代表道路,“1”代表墙壁。
通过标准输出,给出从起点到终点的最短长度。 如果不存在路径,则输出“Fail”。
 
3.基本思路 采用广度优先搜索思路(BFS),从起点出发,计算起点到周围方格的举例,不断扩散范围直至找到终点。 定义一个队列,用于存储即将测量其最短路线长度的方格,然后把起点放入队列,并且初始化步数为1。 然后循环下列操作:
从队列中取出一个方格 
该方格上下左右四个方格如果不是墙壁,加入队列 
如果上下左右四个方格为终点,则直接输出步数作为结果,结束程序 
步数加1 
 
直至队列为空。 如果队列为空导致循环结束,则意味着没有路线能连接起点与终点,输出“Fail”。
 
4.Python实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import  collectionsf = open ("data.txt" , "r" ) input_line = f.readline() input_line = input_line.strip('\n' ) matrix_info = input_line.split(" " ) w = int (matrix_info[0 ]) h = int (matrix_info[1 ]) dirs = [(-1 , 0 ), (0 , 1 ), (1 , 0 ), (0 , -1 )] matrix = [] start_x = 0  start_y = 0  goal_x = 0  goal_y = 0  for  i in  range (0 , h):    input_line = f.readline()     input_line = input_line.strip('\n' )     row = input_line.split(" " )     for  j in  range (0 , w):         if  row[j] == 's' :             start_x = j             start_y = i     matrix.append(row) q = collections.deque() q.append((start_x, start_y)) visited = set () visited.add((start_x, start_y)) step = 1  flag = False  while  q:    for  _ in  range (len (q)):         x, y = q.popleft()         for  dx, dy in  dirs:             nx, ny = x + dx, y + dy             if  0  <= nx < w and  0  <= ny < h and  matrix[ny][nx] != '1'  and  (nx, ny) not  in  visited:                 visited.add((nx, ny))                 q.append((nx, ny))                 if  matrix[ny][nx] == 'g' :                     print (step, end='' )                     flag = True                      break          if  flag:             break      if  flag:         break      step += 1  if  not  flag:    print ('Fail' , end='' ) 
 
 
5.思考过程 最开始拿到这个问题的时候,直观想法是将棋盘抽象为无向图,每一个方格都看作是一个点,可以通行的点(起点、终点、道路)之间具有一条长度为1的边。 然后采用迪杰斯特拉算法求起点到终点的最短路径长度,采用Java实现。 但是在大规模数据上(大小为1000*1000的棋盘上)出现了Runtime Error。 因为是黑盒测试,所以不知道具体数据和错误信息。 因为其他普通数据(100*100以下的棋盘)没有问题,所以很难认为是数组越界等实现上的问题,可能还是数据规模过大导致的内存泄漏的原因。
于是更改思路,尝试了Python实现的A*算法,但是可能与其复杂的数据结构有关,大规模数据上出现了超时(16秒)的问题。 最后尝试了广度优先搜索,大规模数据在1.5秒以内运行完毕,成功通过所有测试数据。
 
6.相关问题 在调查的过程中,发现LeetCode上有一道十分类似的问题:1091. Shortest Path in Binary Matrix 。 只不过这道问题里,角色还可以斜着移动,共有八个移动方向。 解决这个问题,只需要把向量集合改成八个方向就可以了。
1 2 3 4 5 // 上下左右四个方向 dirs = [(-1 , 0 ), (0 , 1 ), (1 , 0 ), (0 , -1 )] // 上下左右+对角线八个方向 dirs = [(-1 , -1 ), (-1 , 0 ), (-1 , 1 ), (0 , 1 ), (1 , 1 ), (1 , 0 ), (1 , -1 ), (0 , -1 )] 
 
 
7.测试数据 最后附上随机测试数据生成器:generator.py 。
 
Reference Source: 
1091. Shortest Path in Binary Matrix (Python)