理解並熟悉掌握深度優先搜尋演算法。
將所學人工智慧理論知識綜合運用到具體專案當中。
有 n 個傳教士和 n 個野人來到河邊渡河,河岸有一條船,每次至多可供 k 人乘渡。問:傳教士為了安全起見,應如何規劃擺渡方案,使得任何時刻, 河兩岸以及船上的野人數目總是不超過傳教士的數目(否則不安全,傳教士有可能被野人吃掉)。 即求解傳教士和野人從左岸全部擺渡到右岸的過程中,任何時刻滿足 m (傳教土數) ≥ c 野人數)和 m+c≤k 的擺渡方案。
假設以傳教士和野人的數量n為3,船一次最大的載人量k為2分析。
初始狀態:河左岸有3個野人河3個傳教士;河右岸有0個野人和0個傳教士;船停在左岸,船上有0個人。
目標狀態:河左岸有0個野人和0個傳教士;河右岸有3個野人和3個傳教士;船停在右岸,船上有0個人。
將整個問題抽象成怎樣從初始狀態經一系列的中間狀態從而達到目標狀態,狀態的改變是通過划船渡河來引發的。
根據要求,共得出以下5中可能的渡河方案:
(1)渡2傳教士
(2)渡2野人
(3)渡1野人1傳教士
(4)渡1傳教士
(5)渡1野人
本程式使用類來定義狀態結點,使用集合儲存狀態結點,使用遞迴(深度優先查詢)的思想來尋找目標狀態。
首先,包含狀態(首次為初始狀態)的結構體結點(已存入結構體陣列)傳入處理函式,然後判斷該傳入結點狀態是否為目標狀態。
是則遍歷列印結構體陣列,列印完成之後,返回遞迴呼叫處,順序執行之後**(此步驟關係到是否能找到所有過河路徑);
否則繼續判斷是否該傳入結點已存在於結構體陣列當中,如存在,不再往下執行,返回遞迴呼叫處,順序執行之後**;
若不存在,則繼續判斷該傳入狀態的人數是否合理(是否出現人物數量小於0的情況等),若不合理,返回遞迴呼叫處,順序執行之後**;
若合理,則繼續判斷傳教士和野人人數限制條件,即在傳教士人數不為0的情況下,野人人數是否大於傳教士人數,若大於則出現吃人的情況,也就是說該傳入狀態也不合理,則返回遞迴呼叫處,順序執行之後**;
若不滿足大於條件,則說明該狀態是路徑轉態,也就是合理的,那麼進行五種渡河方案的依次變換,首先為第一種渡河方案,兩個傳教士過河(注意:此處的5中渡河方案沒有固定順序,也可以是其他渡河方案),那麼對該傳入狀態的左岸和右岸的傳教士人數和野人人數進行增減(若為左岸到右岸,則左岸人數減,右岸人數加,此處有乙個小技巧見本段末尾)。
增減完成並改變船的狀態(使用正負一表示,正一為左岸,負一為右岸)以後就產生了乙個新的狀態,將該狀態存入結構體陣列,之後此處又遞迴呼叫處理函式,將新產生的轉態結點傳入,再次進行上述條件限制判斷。
若在該判斷途中被返回至遞迴呼叫處,說明該狀態不合理,則此時將已經存入結構體陣列的狀態結點移出結構體陣列,然後程式順序執行,進行下乙個渡河方案的處理,也就是說,此時的處理是對上乙個傳入結點的操作(因為剛傳入的已經移出了);
若在判斷途中未被返回至遞迴呼叫處,也就是說,傳入的結點合理了,那麼又開始從第一種渡河方案開始對該傳入狀態進行操作。
按照上述過程迴圈執行,直到出現目標狀態,回到本段開頭,遍歷結構體陣列,列印渡河路徑結點資訊。
完成以後,返回遞迴呼叫處,順序執行之後**,此後的操作是在尋找其他渡河路徑。
原理為:由於該處理函式末尾存在return語句(關鍵),所以在找到目標狀態並返回之後,目標轉態結點同樣會被移出結構體陣列,然後在其上乙個結點開始順序往下執行操作之後的一種渡河方案,檢視是否在該結點處,還有其他渡河方案可以達到目標狀態,若有則同樣按上述方法執行(列印輸出),若執行完後面的所有渡河方案,發現都沒有能夠達到目標狀態的結點,則會執行末尾的返回語句,返回之後,該狀態結點也會被移除(關鍵),那麼此時操作的狀態結點就是上上個結點狀態,對其進行其後的渡河方案操作。按照此法,不斷往後退,直到所有結點都被移除,此時說明已經完成所有渡河路徑的搜尋(深度)。至此,本程式的執行過程敘述完畢。
小技巧:從左岸到右岸,和從右岸到左岸的狀態變化是不一樣的,前者左岸的人數減,右岸的人數加;後者左岸的人數加,右岸的人數減。我們不應單獨再寫程式來處理,而是應該使用船的轉態帶入計算來處理,注意,此技巧在於船的轉態使用正負一來表示,而不應該是1和0,以及其他表示方法。為什麼這麼說?因為任何數乘以一,其本身都不會改變(有我也不會承認)。而正負號在此起到關鍵作用,我們使用正負一去乘以五種渡河方案的改變量值,從而得到的就是我們變換的正確結果,不論左岸右岸,都是正確合理的。
上述原理完全是按照傳教士和野人數量為3人,船一次的載客量最大為2為前提所得。結合上述分析不難看出,當尚未規定傳教士和野人具體數量以及船一次最大載客量為多少時,與之前分析的差別僅僅在於根據人數不同,從河一端到另一端一共有多少中 載客方式,其他的原理流程與傳教士和野人數量為3人,船一次的載客量最大為2的流程全部相同。
主要用來判斷這條方案是否可行。
//遞迴演算法,主要是用來計算船的渡河載客可能性。是否重複操作
for (int i = 0; i < index; i++)}}
//人數是否合理
if (m.left_c < 0 || m.left_y < 0 || m.right_c < 0 || m.right_y < 0
)
//傳教士的人數是否大於等於野人
if ((m.left_c < m.left_y && m.left_c != 0) || (m.right_c < m.right_y && m.right_c != 0
))
//實驗截圖遞迴演算法
for (int cchuan = chuan; cchuan >= 0; cchuan--)}}
運算結束會在「渡河方案」內顯示有多少套可行方案以及每一套方案的具體渡河步驟。
左傳:河左岸傳教士人數\n左野:河左岸野人人數
右傳:河右岸傳教士人數\n右野:河右岸野人人數
船:船現在的位置(1::表示船在河的左岸;-1:表示船在河的右岸)
此程式僅僅實現計算效過,尋找出所有可執行方案,並未開多執行緒進行優化。因此當計算資料過大時,介面程序堵塞,會造成程式停止響應,不過不用擔心,程式依舊在後台運算。當程式使用足夠時間執行完畢後,程式將會重新響應並展示所有的可行方案!計算需要一定的時間,計算過程中請耐心等待。
通過本次試驗,掌握學會了深度優先搜尋演算法。
能夠很好的將所學人工智慧理論知識綜合運用到具體專案當中。
傳教士野人過河問題
這個問題是人工智慧中經典的搜尋問題,下面用深度優先搜尋演算法來解這個題,示例 如下 include include include using namespace std typedef struct mcnode listfringe 相當於佇列 vectorclosed closed表 判斷是否...
野人與傳教士過河問題
題目 設有三個 傳教士和3個野人來到河邊,打算乘乙隻船從右岸渡到左岸去。該船的負載能力為兩個人。在任何時候,如果野人人數超過傳教士人數那麼野人就會把傳教士吃掉。他們怎樣才能用這條船安全地把所有人都渡過河去?河岸 a 對岸 b 船上 2c 2y 1c 1y回去 傳教士划船回去 河岸 a 對岸 b 船上...
傳教士與野人過河問題
360公司 2012年校園招聘會筆試題演算法題 傳教士和野人問題 missionaries and cannibals 這是乙個經常在有關討論人工智慧的書籍中見到的問題,其描述是這樣的 有n個傳教士和n個野人來到河邊渡河,河岸有一條船,每次至多可供k人乘渡。問傳教士為了安全起見,應如何規劃擺渡方案,...