八數碼問題(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()