二维

1、岛屿数量

image.png

(1)、遇到1就DFS

  1. class Solution:
  2. def numIslands(self, grid: List[List[str]]) -> int:
  3. if not grid: return 0
  4. row = len(grid)
  5. col = len(grid[0])
  6. cnt = 0
  7. def dfs(i, j):
  8. grid[i][j] = "0" # 设置为0,防止重复访问
  9. for x, y in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
  10. tmp_i = i + x
  11. tmp_j = j + y
  12. if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1":
  13. dfs(tmp_i, tmp_j)
  14. for i in range(row):
  15. for j in range(col):
  16. if grid[i][j] == "1":
  17. dfs(i, j)
  18. cnt += 1
  19. return cnt

(2)、遇到1就BFS

这两个没有什么区别,因为BFS没有终止条件,两个方法都把1遍历完了

  1. class Solution:
  2. def numIslands(self, grid: List[List[str]]) -> int:
  3. from collections import deque
  4. if not grid: return 0
  5. row = len(grid)
  6. col = len(grid[0])
  7. cnt = 0
  8. def bfs(i, j):
  9. queue = deque()
  10. queue.appendleft((i, j))
  11. grid[i][j] = "0"
  12. while queue:
  13. i, j = queue.pop()
  14. for x, y in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
  15. tmp_i = i + x
  16. tmp_j = j + y
  17. if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1":
  18. grid[tmp_i][tmp_j] = "0"
  19. queue.appendleft((tmp_i, tmp_j))
  20. for i in range(row):
  21. for j in range(col):
  22. if grid[i][j] == "1":
  23. bfs(i, j)
  24. cnt += 1
  25. return cnt

2、允许对称转移的二维迷宫image.png

多考虑一种走法

  1. import sys
  2. from collections import deque
  3. def check(grid, x, y, s):
  4. return 0 <= x < len(grid) and 0 <= y < len(grid[0]) and 0 <= s <= 5 and grid[x][y] != '#'
  5. def bfs(grid, x, y, s):
  6. n, m = len(grid), len(grid[0])
  7. queue = deque()
  8. # 事实上有了res表,不用再使用最后一位来记录结果了,而且(x,y,s)才是定义的搜索状态。但是这样写可以与不用res表的代码统一起来
  9. queue.append((x, y, s, 0))
  10. # 转移表,每个二元组表示x和y的增量
  11. transitions = [[-1, 0], [1, 0], [0, -1], [0, 1]] # s坐标后面手动控制其转移
  12. # 搜索状态定义为(x,y,s),所以不再适合直接使用原矩阵记录是否已经访问
  13. # 这里设置res来保存搜索结果,默认值-1还可以用于判断是否已经访问
  14. res = [[[-1 for _ in range(5)] for _ in range(m)] for _ in range(n)]
  15. res[x][y][s] = 0 # 设置起点的最小时间代价为0
  16. while queue:
  17. x, y, s, t = queue.popleft()
  18. for i in range(5): # 5种走法:上下左右以及对称
  19. if i < 4: # 上下左右可以使用transitions统一处理
  20. d = transitions[i]
  21. nx, ny, ns, nt = x + d[0], y + d[1], s, t + 1
  22. else: # 对称转移时,新坐标不是简单用一个增量加到原坐标,而是原坐标的函数,所以手动控制转移结果
  23. nx, ny, ns, nt = n - 1 - x, m - 1 - y, s + 1, t + 1
  24. if check(grid, nx, ny, ns) and res[nx][ny][ns] == -1: # 如果下一个状态是合法的,且未访问过
  25. if grid[nx][ny] == 'E': # 如果是所求的终点,返回对应的结果时间
  26. return nt
  27. queue.append((nx, ny, ns, nt)) # 否则入队,后续再访问其邻接结点
  28. res[nx][ny][ns] = nt # 记录到达该结点的最小时间,同时也表示已经访问过
  29. return -1
  30. # 起点状态,x、y为箱子的左上角格子坐标,s为已经使用飞行器的次数,t为步数/时间
  31. time = bfs(grid, x, y, s)
  32. print(time)

2.5维

1、推箱子

image.png

  1. import sys
  2. from collections import deque
  3. def parse_nums(nums_str):
  4. return [int(x) for x in nums_str.strip().split()]
  5. def check(grid, x, y, s):
  6. if x < 0 or x > len(grid) or y < 0 or y > len(grid[0]):
  7. return False # 如果出界,不合法
  8. if grid[x][y] == '#':
  9. return False # 如果箱子的坐标对应的格子是禁地,不合法
  10. if s == 0 and grid[x][y] == 'E':
  11. return False # 如果箱子是竖着的,则箱子对应坐标是易碎也不合法
  12. if s == 1 and grid[x][y + 1] == '#':
  13. return False # 如果箱子是左右的,则箱子的另一个格子如果是禁地也不合法
  14. if s == 2 and grid[x + 1][y] == '#':
  15. return False # 如果箱子是上下的,则箱子的另一个格子如果是禁地也不合法
  16. return True
  17. def bfs(grid, x, y, s):
  18. queue = deque()
  19. # 事实上有了res表,不用再使用最后一位来记录结果了,而且(x,y,s)才是定义的搜索状态。但是这样写可以与不用res表的代码统一起来
  20. queue.append((x, y, s, 0))
  21. # 转移表,每个三元组的前两个表示x和y的增量,第三个表示箱子姿势的转移
  22. transitions = [[[-2, 0, 2], [1, 0, 2], [0, -2, 1], [0, 1, 1]], # 姿势为竖着对应的4个方向的x,y,s如何转移
  23. [[-1, 0, 1], [1, 0, 1], [0, -1, 0], [0, 2, 0]], # 姿势为左右对应的4个方向的x,y,s如何转移
  24. [[-1, 0, 0], [2, 0, 0], [0, -1, 2], [0, 1, 2]]] # 姿势为上下对应的4个方向的x,y,s如何转移
  25. # 搜索状态定义为(x,y,s),所以不再适合直接使用原矩阵记录是否已经访问
  26. # 这里设置res来保存搜索结果,默认值-1还可以用于判断是否已经访问
  27. res = [[[-1 for _ in range(3)] for _ in range(len(grid[0]))] for _ in range(len(grid))]
  28. res[x][y][s] = 0 # 设置起点的最小时间代价为0
  29. while queue:
  30. x, y, s, t = queue.popleft()
  31. for d in transitions[s]: # 用s取出转移表中对应的行
  32. nx, ny, ns, nt = x + d[0], y + d[1], d[2], t + 1 # 状态转移与结果记录(注意d[2]不是增量,所以ns=d[2]而不是=s+d[2])
  33. if check(grid, nx, ny, ns) and res[nx][ny][ns] == -1: # 如果下一个状态是合法的,且未访问过
  34. if grid[nx][ny] == 'O' and ns == 0: # 如果是所求的终点,返回对应的结果时间
  35. return nt
  36. queue.append((nx, ny, ns, nt)) # 否则入队,后续再访问其邻接结点
  37. res[nx][ny][ns] = nt # 记录到达该结点的最小时间,同时也表示已经访问过
  38. return -1
  39. # 读取2维地图
  40. for ns in sys.stdin:
  41. if ns == '0 0': # 终止信号
  42. break
  43. N, M = parse_nums(ns)
  44. grid = []
  45. # 起点状态,x、y为箱子的左上角格子坐标,s为箱子姿势(0为竖着,1为左右躺着,2为上下躺着),t为步数/时间
  46. x, y, s, t = 0, 0, 0, 0
  47. first_X = True
  48. for i in range(N):
  49. row = [c for c in input()]
  50. if 'X' in row:
  51. if first_X: # 第一次碰到X,就能判断是否为左右躺着,否则先默认竖着
  52. x, y, s = i, row.index('X'), 0
  53. if row[y + 1] == 'X':
  54. s = 1
  55. first_X = False
  56. else: # 如果碰到了两行中都有X,则是上下躺着
  57. s = 2
  58. grid.append(row)
  59. time = bfs(grid, x, y, s)
  60. print(time if time != -1 else 'Impossible')

三维

1、迷宫image.png

  1. import sys
  2. from collections import deque
  3. def parse_nums(nums_str):
  4. return [int(x) for x in nums_str.strip().split()]
  5. def bfs(grid, x, y, z):
  6. queue = deque()
  7. queue.append((x, y, z, 0))
  8. grid[x][y][z] = '#' # 不走回头路
  9. while queue:
  10. directions = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]]
  11. x, y, z, t = queue.popleft()
  12. for d in directions: # 选择列表
  13. nx, ny, nz, nt = x + d[0], y + d[1], z + d[2], t + 1 # 索引
  14. if 0 <= nx < len(grid) and 0 <= ny < len(grid[0])
  15. and 0 <= nz < len(grid[0][0]) and grid[nx][ny][nz] != '#': # 满足条件,加入队列
  16. if grid[nx][ny][nz] == 'E':
  17. return nt
  18. queue.append((nx, ny, nz, nt))
  19. grid[nx][ny][nz] = '#' # 不走回头路
  20. return -1
  21. for ns in sys.stdin:
  22. if ns == '0 0 0': # 终止信号
  23. break
  24. L, R, C = parse_nums(ns) # 层数、行数、列数
  25. grid = []
  26. x, y, z = 0, 0, 0
  27. for i in range(L):
  28. level = []
  29. for j in range(R):
  30. row = [c for c in input()]
  31. if 'S' in row: # 起始点
  32. x, y, z = i, j, row.index('S')
  33. level.append(row)
  34. grid.append(level)
  35. input() # 丢弃空行
  36. time = bfs(grid, x, y, z)
  37. print("Trapped!" if time == -1 else f"Escaped in {time} minute(s).")

进阶版 会掉血

  1. def bfs(grid, x, y, z):
  2. queue = deque()
  3. queue.append((x, y, z, 0))
  4. grid[x][y][z] = '#' # 不走回头路
  5. while queue:
  6. directions = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]]
  7. x, y, z, t, n = queue.popleft()
  8. for d in directions: # 选择列表
  9. nx, ny, nz, nt = x + d[0], y + d[1], z + d[2], t + 1 # 索引
  10. if 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) and 0 <= nz < len(grid[0][0])
  11. and grid[nx][ny][nz] != '#' and nn>0: # 满足条件,加入队列
  12. if grid[nx][ny][nz] == 'E':
  13. return nt
  14. if grid[nx][ny][nz]=='*'":
  15. nn-=1
  16. else:
  17. nn=nn
  18. queue.append((nx, ny, nz, nt, nn))
  19. grid[nx][ny][nz] = '#' # 不走回头路
  20. return -1