Python基于回溯法子集樹模板解決野人與傳教士問題示例
本文實例講述了Python基于回溯法子集樹模板解決野人與傳教士問題。分享給大家供大家參考,具體如下:
問題
在河的左岸有N個傳教士、N個野人和一條船,傳教士們想用這條船把所有人都運過河去,但有以下條件限制:
(1)修道士和野人都會劃船,但船每次最多只能運M個人;
(2)在任何岸邊以及船上,野人數(shù)目都不能超過修道士,否則修道士會被野人吃掉。
假定野人會服從任何一種過河安排,請規(guī)劃出一個確保修道士安全過河的計劃。
分析
百度一下,網(wǎng)上全是用左岸的傳教士和野人人數(shù)以及船的位置這樣一個三元組作為狀態(tài),進行考慮,千篇一律。
我換了一種考慮,只考慮船的狀態(tài)。
船的狀態(tài):(x, y) x表示船上x個傳教士,y表示船上y個野人,其中 |x|∈[0, m], |y|∈[0, m], 0<|x|+|y|<=m, x*y>=0, |x|>=|y|
船從左到右時,x,y取非負數(shù)。船從右到左時,x,y取非正數(shù)
解的編碼:[(x0,y0), (x1,y1), ..., (xp,yp)] 其中x0+x1+...+xp=N, y0+y1+...+yp=N
解的長度不固定,但一定為奇數(shù)
開始時左岸(N, N), 右岸(0, 0)。最終時左岸(0, 0), 右岸(N, N)
由于船的合法狀態(tài)是動態(tài)的、二維的。因此,使用一個函數(shù)get_states()
來專門生成其狀態(tài)空間,使得主程序更加清晰。
代碼
n = 3 # n個傳教士、n個野人 m = 2 # 船能載m人 x = [] # 一個解,就是船的一系列狀態(tài) X = [] # 一組解 is_found = False # 全局終止標志 # 計算船的合法狀態(tài)空間(二維) def get_states(k): # 船準備跑第k趟 global n, m, x if k%2==0: # 從左到右,只考慮原左岸人數(shù) s1, s2 = n - sum(s[0] for s in x), n - sum(s[1] for s in x) else: # 從右到左,只考慮原右岸人數(shù)(將船的歷史狀態(tài)累加可得?。。。? s1, s2 = sum(s[0] for s in x), sum(s[1] for s in x) for i in range(s1 + 1): for j in range(s2 + 1): if 0 < i+j <= m and (i*j == 0 or i >= j): yield [(-i,-j), (i,j)][k%2==0] # 生成船的合法狀態(tài) # 沖突檢測 def conflict(k): # 船開始跑第k趟 global n, m, x # 若船上載的人與上一趟一樣(會陷入死循環(huán)?。。。。? if k > 0 and x[-1][0] == -x[-2][0] and x[-1][1] == -x[-2][1]: return True # 任何時候,船上傳教士人數(shù)少于野人,或者無人,或者超載(計算船的合法狀態(tài)空間時已經(jīng)考慮到了。) #if 0 < abs(x[-1][0]) < abs(x[-1][1]) or x[-1] == (0, 0) or abs(sum(x[-1])) > m: # return True # 任何時候,左岸傳教士人數(shù)少于野人 if 0 < n - sum(s[0] for s in x) < n - sum(s[1] for s in x): return True # 任何時候,右岸傳教士人數(shù)少于野人 if 0 < sum(s[0] for s in x) < sum(s[1] for s in x): return True return False # 無沖突 # 回溯法 def backtrack(k): # 船準備跑第k趟 global n, m, x, is_found if is_found: return # 終止所有遞歸 if n - sum(s[0] for s in x) == 0 and n - sum(s[1] for s in x) == 0: # 左岸人數(shù)全為0 print(x) is_found = True else: for state in get_states(k): # 遍歷船的合法狀態(tài)空間 x.append(state) if not conflict(k): backtrack(k+1) # 深度優(yōu)先 x.pop() # 回溯 # 測試 backtrack(0)
效果圖
解的解釋,從上往下看:
一個結(jié)論
貌似只有滿足m = n-1
,此問題才有解。
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計有所幫助。
相關(guān)文章
python pandas模塊進行數(shù)據(jù)分析
Python的Pandas模塊是一個強大的數(shù)據(jù)處理工具,可以用來讀取、處理和分析各種數(shù)據(jù),本文主要介紹了python pandas模塊進行數(shù)據(jù)分析,具有一定的參考價值,感興趣的可以了解一下2024-01-01python?tkinter庫的Text記錄點擊路經(jīng)和刪除記錄詳情
這篇文章主要介紹了python?tkinter庫的Text記錄點擊路經(jīng)和刪除記錄詳情,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下2022-06-06對python中Matplotlib的坐標軸的坐標區(qū)間的設(shè)定實例講解
今天小編就為大家分享一篇對python中Matplotlib的坐標軸的坐標區(qū)間的設(shè)定實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05Python中的條件判斷語句與循環(huán)語句用法小結(jié)
這篇文章主要介紹了Python中的條件判斷語句與循環(huán)語句用法小結(jié),條件語句和循環(huán)語句是Python程序流程控制的基礎(chǔ),需要的朋友可以參考下2016-03-03