#数字华容道#广度优先算法,bfs
3×3的数字华容道想必大家都玩过,利用python算法也可以实现华容道的快速回正
输入: 一个数字从 1 到 8 的矩阵,作为包含整数的列表列表。
输出: 空单元格的字符串路由。
例:
checkio([[1, 2, 3],
[4, 6, 8],
[7, 5, 0]]) == “ULDR”
1
2
3
使用方法: 此任务中概念最明显的用途在于创建一个机器人来解决幻灯片谜题; 然而,这个任务也是一种学习新事物的有趣方式,因为 n 谜题是涉及启发式算法建模的经典问题。
前提条件:
len(puzzle) == 3
all(len(row) == 3 for row in puzzle)
from collections import deque
def countInversion(puzzle, blankpos):
"""8 puzzle问题存在定理,即当面对N×N的puzzle,如果逆序对的个数的奇偶性恰好相反则有解,因此编写一个函数用来计算被扁平化后的puzzle存在多少组逆序对,来筛除不合法的情况"""
inversion = 0
puzzle.pop(blankpos)
for i in range(len(puzzle)):
for j in range(i+1, len(puzzle)):
if puzzle[i] > puzzle[j]:
inversion += 1
puzzle.insert(blankpos, 0)
return inversion
def checkio(puzzle):
"""此函数先将puzzle扁平化,然后创建一个访问集合用来存储父级puzzle,然后将路径,空格位置,以及子级puzzle打包。通过队列实现广度优先算法,遍历当前空格位置对应的父级puzzle存在的所有子级情况。设置一定的筛选条件,比如一维数组在二维空间的障碍,会导致某些移动不合法,因此可以在step步数上节省时间。同时对于计算的空格的下一个位置所组成的子级puzzle是否可解,当可解时,保存。"""
directions = {
"U": -3, "D": +3, "L": -1, "R": +1
}
puzzle = [item for sublist in puzzle for item in sublist]
# 创造一个访问集合
visited = set()
# 创造一个队列,并将空格位置作为父级节点,加入
queue = deque([(puzzle.index(0), tuple(puzzle), "")])
while queue:
vertex, puzzle, path = queue.popleft()
if puzzle == (1, 2, 3, 4, 5, 6, 7, 8, 0):
return path
visited.add(puzzle)
for dir, step in directions.items():
if (vertex % 3 == 0 and step == -1) or (vertex % 3 == 2 and step == +1):
continue # 第一列和最后一列,不能左右移动
if vertex < 3 and step == -3:
continue # 第一行,不能上移
if vertex >= 6 and step == +3:
continue # 最后一行,不能下移
next_pos = vertex+step
test_puzzle = list(puzzle)
test_puzzle[vertex], test_puzzle[next_pos] = test_puzzle[next_pos], test_puzzle[vertex]
if countInversion(test_puzzle, next_pos) % 2 == 0:
if tuple(test_puzzle) not in visited:
queue.append((next_pos, tuple(test_puzzle), path+dir))
return None
checkio([[1, 2, 3],
[4, 6, 8],
[7, 5, 0]])