广度优先搜索-八数码问题
八数码问题(Eight):八数码问题是人工智能中的经典问题
有一个3*3的棋盘,其中有0-8共9个数字,0表示空格,
其他的数字可以和0交换位置。求由初始状态
到达目标状态
8 2 3 1 2 3
1 4 6 ----> 4 5 6
5 7 0 7 8 0
的步数最少的解。
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。
棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。
要求解的问题是:给出一种初始布局(初始状态)和目标布局
(为了使题目简单,设目标状态为123456780),找到一种最少步骤的移动方法,
实现从初始布局到目标布局的转变。
输入格式:输入初始状态,一行九个数字,空格用0表示
123406758
823146570
输出格式:只有一行,该行只有一个数字,表示从初始状态到目标状态需要的
最少移动次数(测试数据中无特殊无法到达目标状态数据)
2
18
https://www.cnblogs.com/czc1999/p/10428066.html
https://blog.csdn.net/yangysc/article/details/50710439
python代码实现:
1 # 目标状态 2 goal_status = 123456780 3 # 四种移动方向 4 moves = ["u", "d", "r", "l"] 5 myQueue = [0 for i in range(400000)] # 状态队列,状态总数362880,对每种状态进行插入或者移除 6 qHead = 0 # 队头指针 7 qTail = 1 # 队尾指针 8 9 10 class Node: 11 status = 0 # 状态 12 father = 0 # 父节点指针,即myQueue的下标 13 move = "" # 父节点到本节点的移动方式 u/d/r/l 14 15 def __init__(self, s, f, m): 16 self.status = s 17 self.father = f 18 self.move = m 19 20 21 # 求从status经过move移动后得到的新状态。若移动不可行则返回-1 22 def NewStatus(status, move): 23 zeroPos = 0 # 字符'0'的位置 24 # 不足9位时,前面补0 25 tmp = str(status).zfill(9) 26 zeroPos = tmp.find('0') 27 temp_list = list(tmp) 28 if move == "u": 29 if zeroPos - 3 < 0: # 空格在第一行 30 return -1 31 else: 32 temp_list[zeroPos] = temp_list[zeroPos - 3] 33 temp_list[zeroPos - 3] = '0' 34 elif move == "d": 35 if zeroPos + 3 > 8: # 空格在第三行 36 return -1 37 else: 38 temp_list[zeroPos] = temp_list[zeroPos + 3] 39 temp_list[zeroPos + 3] = '0' 40 elif move == "l": 41 if zeroPos % 3 == 0: # 空格在第一列 42 return -1 43 else: 44 temp_list[zeroPos] = temp_list[zeroPos-1] 45 temp_list[zeroPos-1] = '0' 46 elif move == "r": 47 if zeroPos % 3 == 2: # 空格在第三列 48 return -1 49 else: 50 temp_list[zeroPos] = temp_list[zeroPos+1] 51 temp_list[zeroPos+1] = '0' 52 tmp = "".join(temp_list) 53 return int(tmp) 54 55 56 def bfs(status): 57 global qHead, qTail, goal_status, moves 58 # 把每个状态都存入该set中,set有判重的功能 59 expanded = set() 60 # 初始状态放入队头 61 myQueue[qHead] = Node(status, -1, 0) 62 # 把初始状态存入set集合 63 expanded.add(status) 64 # 队列不为空 65 while qHead != qTail: 66 status = myQueue[qHead].status 67 if status == goal_status: # 找到目标状态 68 return True 69 for i in range(4): # 尝试4种移动方向 70 # 根据moves[i]列表的方向移动,产生一个新的数 71 newStatus = NewStatus(status, moves[i]) 72 # 不可移,试下一个方向 73 if newStatus == -1: 74 continue 75 # 已扩展过,试下一个方向 76 if newStatus in expanded: 77 continue 78 # 把新方向的状态整数值加入到队列中 79 expanded.add(newStatus) 80 # 按广度优先遍历的思路理解的话,qHead应该理解为层 81 # 也就是新加入的这个节点是从哪层的某个状态转变过来的 82 myQueue[qTail] = Node(newStatus, qHead, moves[i]) 83 qTail += 1 84 85 qHead += 1 86 87 return False 88 89 90 def main(): 91 global qHead, myQueue 92 result = [0 for i in range(400000)] # 要输出的移动方案 93 start_status = int(input()) 94 if bfs(start_status): 95 n = 0 96 pos = qHead 97 # pos = 0 说明已经回退到初始状态了 98 while pos != 0: 99 # 通过father找到成功的状态序列,输出相应步骤 100 # 从后往前找 101 # kk = myQueue[pos].status 102 result[n] = myQueue[pos].move 103 pos = myQueue[pos].father 104 n += 1 105 print("共需要移动%d步" % n) 106 print("具体的移动步骤如下:") 107 for i in range(n-1, -1, -1): 108 print(result[i]) 109 else: 110 print("不能转换到该状态!") 111 112 return 0 113 114 115 if __name__ == '__main__': 116 main()