python實現三壺謎題的示例詳解
阿新 • • 發佈:2020-11-04
前言
有一個充滿水的8品脫的水壺和兩個空水壺(容積分別是5品脫和3品脫)。通過將水壺完全倒滿水和將水壺的水完全倒空這兩種方式,在其中的一個水壺中得到4品脫的水。
一、演算法思想
演算法分析
- 採用的演算法思想是將某個時刻水壺中水的數量看作一個狀態,用一個長度為3的陣列表示。
- 初始狀態便為[8,0],再拓展他的下一結點的可能結構。
- 若下一結點的結構已經被拓展過了便放棄,若沒有拓展過則加入拓展列表(open_list)中。然後遞迴上述操作。
- 直到拓展列表(open_list)為空或者找到目標為止。
思想圖解
這裡的第一個數就代表著是那個8品脫的瓶子,依次分別是8品脫,5品脫,3品脫
就如同上圖一樣,使用層次遍歷一次一次遞迴擴充套件新的結點,知道找到4品脫的水或者無結點可擴充套件為止(類似於廣度優先遍歷)。
二、程式碼展示
1.建立樹節點結構
節點包括兩個屬性,一個屬性是陣列型別的,儲存當前三個水壺的容量狀態,另一個屬性是記錄它是由哪個結點擴充套件過來的,以便找到解決路徑:
class node: # 建立樹節點 def __init__(self,data): self.data = data # 儲存三個壺的容量狀態 self.per = None # 儲存上一時刻三個壺的容量狀態
2.實現傾倒動作
由於這裡只有三個壺,互相傾倒的方案可以枚舉出來,所有我就沒使用二重巢狀迴圈,而是使用一層迴圈:
def pour(n): # 擴充套件子節點 r_list = n.data # 記錄當前三個水壺的容量狀態 max_list = [8,5,3] # 水壺的最大容量 for i,j in ((0,1),(0,2),(1,0),(2,1)): if r_list[i] != 0: n_list = r_list.copy() # 初始化下一結點的水壺狀態 if r_list[i] + r_list[j] > max_list[j]: n_list[i] = r_list[i] - (max_list[j] - r_list[j]) n_list[j] = max_list[j] else: n_list[j] = r_list[i] + r_list[j] n_list[i] = 0 flag = True # 記錄水壺的狀態是否已經發生過(擴充套件過) for one in closed_list: if one.data == n_list: # 比較當前水壺狀態和以往記錄過得水壺狀態 flag = False if flag: print("擴充套件的新節點是:",n_list) new_node = node(n_list) # 建立新節點儲存水壺的新狀態 new_node.per = n open_list.append(new_node)
主遞迴函式
檢視當前是否已經擴充套件到4品脫的水或者是否還有結點可以擴充套件。
def BFS_node(root_1): # 遞迴查詢子節點的擴充套件狀態以及查驗是否找到4品脫的水壺 n = root_1 print("當前節點:",n.data) if open_list is None: return "沒有找到4品脫的水" nodelist = n.data if 4 in nodelist: print("找到了4品脫的水") print_node(n) return "找到了4品脫的水" closed_list.append(open_list.pop(0)) pour(n) print("*******") BFS_node(open_list[0])
資料初始化
資料初始化,以及找到4品脫水後列印路徑的列印函式。
def print_node(n): # 列印正確的水壺操作路徑 if n.per == None: return "" print(n.data) print_node(n.per) # 初始化資料 root = node([8,0]) open_list = [root] # 儲存已找到卻未被擴充套件的子節點 closed_list = [] # 儲存已找到且被擴充套件的子節點 BFS_node(open_list[0])
總結
主要是用廣度優先遍歷的思想和樹結構,當然如果不在意找到4品脫的水的路徑,其實沒必要使用樹結構。另外列印函式是從最後一層依次往上回溯的,所以顯示的是倒序的路徑。如果需要變成正向的話,可以加一個棧來實現。
到此這篇關於python實現三壺謎題的示例詳解的文章就介紹到這了,更多相關python三壺謎題內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!