廣度優先搜索-八數碼問題


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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM