#BFS算法node
###1.走迷宮的最短路徑 問題: 給出一個起點和終點, 求起點走到終點的最短距離.
思路: 每層節點爲4^n的樹, 搜到符合結果的節點便可.
起點(0,0) 終點(4,4) 1爲牆(不可走)
python codepython
from queue import Queue M = [ [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0], ] V = [[False for j in range(5)] for i in range(5)] dx = [-1, 1, 0, 0] dy = [ 0, 0, -1, 1] class Node: def __init__(self, x, y, step): self.x, self.y, self.step = x, y, step def bfs(start_x, start_y): que = Queue() que.put(Node(start_x, start_y, 0)) while not que.empty(): node = que.get() x, y, step = node.x, node.y, node.step for i in range(4): nx, ny = x+dx[i], y+dy[i] if nx<0 or ny<0 or nx>4 or ny>4: continue if V[nx][ny] or M[nx][ny]==1: continue if nx==4 and ny==4: return step+1 que.put(Node(nx, ny, step+1)) V[nx][ny] = True ans = bfs(0, 0) print(ans)
###2.八數碼(九宮問題) 問題: 3×3棋盤上有1~8的數字和一個空格, 每次移動空格能夠和相鄰數字交換,給出一個初始狀態和一個目標狀態, 找出最少的移動步驟.
思路: 同走迷宮, 中途產生的狀態處理比以前麻煩一點.算法
須要把已經出現過的狀態記錄在集合中, 防止重複樹節點致使搜索樹進行不下去.
python不支持將列表放在集合中,用技巧進行轉換, 存整數.
python code函數
from queue import Queue import copy M = [ [0, 8, 7], [6, 5, 4], [3, 2, 1] ] T = [ [1, 2, 3], [4, 5, 6], [7, 8, 0] ] S = set() dx = [-1, 1, 0, 0] dy = [ 0, 0, -1, 1] class Node: def __init__(self, x, y, stat, step): self.x, self.y = x, y self.stat, self.step = stat, step def calc_value(stat): weight, sum = 1, 0 for i in range(3): for j in range(3): sum += stat[i][j]*weight weight *= 10 return sum def bfs(): que = Queue() start_node = Node(0, 0, copy.deepcopy(M), 0) que.put(start_node) while not que.empty(): node = que.get() x, y = node.x, node.y stat, step = node.stat, node.step S.add(calc_value(stat)) for i in range(0, 4): nx, ny = x+dx[i], y+dy[i] if nx<0 or ny<0 or nx>2 or ny>2: continue new_stat = copy.deepcopy(stat) new_stat[nx][ny], new_stat[x][y] = new_stat[x][y], new_stat[nx][ny] if calc_value(new_stat) in S: continue if new_stat == T: return step+1 que.put(Node(nx, ny, new_stat, step+1)) ans = bfs() print(ans)
能夠在生成狀態前先計算value, 不過提高的速度很少.
再增長一個類屬性last_node來連接上一個狀態, 打印倒着的變化過程.
python codecode
from queue import Queue import copy M = [ [0, 8, 7], [6, 5, 4], [3, 2, 1] ] T = [ [1, 2, 3], [4, 5, 6], [7, 8, 0] ] S = set() dx = [-1, 1, 0, 0] dy = [ 0, 0, -1, 1] class Node: def __init__(self, x, y, stat, step, last_node): self.x, self.y = x, y self.stat, self.step = stat, step self.last_node = last_node def calc_value(stat): weight, sum = 1, 0 for i in range(3): for j in range(3): sum += stat[i][j]*weight weight *= 10 return sum def swap_stat(stat, x, y, nx, ny): stat[x][y], stat[nx][ny] = stat[nx][ny], stat[x][y] def bfs(): que = Queue() start_node = Node(0, 0, M, 0, None) que.put(start_node) while not que.empty(): node = que.get() x, y = node.x, node.y stat, step = node.stat, node.step S.add(calc_value(stat)) for i in range(0, 4): nx, ny = x+dx[i], y+dy[i] if nx<0 or ny<0 or nx>2 or ny>2: continue swap_stat(stat, x, y, nx, ny) if calc_value(stat) in S: swap_stat(stat, x, y, nx, ny) continue if stat == T: return step+1, node new_stat = copy.deepcopy(stat) swap_stat(stat, x, y, nx, ny) que.put(Node(nx, ny, new_stat, step+1, node)) ans, node = bfs() print(ans) while node.last_node != None: print(node.stat) node = node.last_node
###優先隊列BFS 依然是走迷宮, 不過此次判斷的是最短期 增長三秒(遇到2), 因此最優不是那條路.隊列
from queue import PriorityQueue M = [ [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 2], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0] ] V = [[False for j in range(5)] for i in range(5)] dx = [-1, 1, 0, 0] dy = [ 0, 0, -1, 1] class Node: def __init__(self, x, y, step, time): self.x, self.y = x, y self.step, self.time = step, time def __lt__(self, other): if self.time > other.time: return True return False def bfs(start_x, start_y): que = PriorityQueue() que.put(Node(start_x, start_y, 0, 0)) while not que.empty(): node = que.get() x, y = node.x, node.y step, time = node.step, node.time for i in range(4): nx, ny = x+dx[i], y+dy[i] if nx<0 or ny<0 or nx>4 or ny>4: continue if V[nx][ny] or M[nx][ny]==1: continue if nx==4 and ny==4: return time+1 t = V[nx][ny]+1 que.put(Node(nx, ny, step+1, time+t)) V[nx][ny] = True ans = bfs(0, 0) print(ans)
###三維立方體迷宮BFS的解法 多增長几個方向, 在類中多增長一個成員z, 對應修改bfs函數便可.get
dx = [0, 0, 1, 0, 0, -1] dy = [0, 1, 0, 0, -1, 0] dz = [1, 0, 0, -1, 0, 0] class Node: def __init__(self, x, y, z, step): self.x, self.y, self.z, self.step = x, y, z, step