BFS算法

#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
相关文章
相关标签/搜索