现已知一个大小为N · M的地图,地图中只有可能出现两个数字:0或1,现规定如果位于数字为0的格子上,则下一步只能往相邻四个格子中数字为1的格子走,如果位于数字为1的格子上,则下一步只能往相邻四个格子中数字为0的格子走。如果给定起点格子,则可以向上下左右四个方向移动,且同一个格子不能重复走,求能在地图中到达多少格子?
如图所示,起点为左上角1,课堂到达地图上的所有方格。因此,图7-16所示的地图可以求解出的答案应为16.
如图所示,起点为左上角1,但因为其右边和下方的方格均为1,因此无法移动到任何其他方格中,求解出能到达的格子数为1。
广度优先搜索算法的核心思想是队列,先创建一个队列结构。因为广度优先搜索算法优先搜索离起始点最近的点,所以可以通过判断现在位于的方格的上下左右四个方格是否能到达来构建队列。如果可以到达,则加入队列的末尾,如果不能到达则跳过。以这种方式来更新队列,可以保证每一种移动方案均能被考虑到。而为了不重复遍历相同的路径,需用一个列表来存储一个格子是否被加入队列过,防止浪费计算资源。
from queue import Queue
import numpy as np
Q = Queue() # 建立队列
class grid: # 定义grid类,其中每一个方格(grid)都含有行(row)和列(col)属性
def __init__(self, row, col):
self.row = row
self.col = col
def bfs(self, val, startrow, startcol):
row = len(val) # val是存储地图的二位列表,row变量为其行数
col = len(val[0]) # col变量为地图的列数
arrived = [[False for j in range(int(col))] for i in range(int(row))]
# arrived二维列表存储地图上每个方格是否已经到达过(已经进入过队列)
moverow = [0, 1, 0, -1]
# moverow数组存储向相邻方格移动时行的变化情况分别为增加1(1),减少1(-1),和不变(0)
movecol = [1, 0, -1, 0]
# moverow数组存储向相邻方格移动时列的变化情况,与moverow原理相同
ans = 1
# put()是用在队列(Queue)模块中的一个函数,将一个元素添加到队列的末尾
Q.put(grid(int(startrow), int(startcol))) # 将起点加入队列
arrived[int(startrow)][int(startcol)] = True # 将起点设为已到达过
while not Q.empty(): # 判断队列是否为空
# get()是队列的一个方法,用于从队列中移除并返回队首的元素
cur = Q.get() # 取出队列首位的元素
for i in range(4):
# 遍历moverow和movecol,其实就是向现所位于的方格的四个方向的移动
newrow = cur.row + moverow[i]
newcol = cur.col + movecol[i]
if newrow > row - 1 or newrow < 0 or newcol > col - 1 or newcol < 0:
# 判断移动后是否超界
continue
if not arrived[newrow][newcol] and \
val[newrow][newcol] != val[cur.row][cur.col]: # 判断是否已经到达过,是否与起始点的数值不同
Q.put(grid(newrow, newcol)) # 将发现可以到达的新方格放入队列中
arrived[newrow][newcol] = True # 将可到达的新方格设为已到达过
ans += 1 # 求得答案
return ans
输入
图示
输出