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