360公司 2023年校園招聘會筆試題演算法題
傳教士和野人問題(missionaries and cannibals)
這是乙個經常在有關討論人工智慧的書籍中見到的問題, 其描述是這樣的:
有n個傳教士和n個野人來到河邊渡河, 河岸有一條船, 每次至多可供k人乘渡。問傳教士為了安全起見, 應如何規劃擺渡方案, 使得任何時刻, 河兩岸以及船上的野人數目總是不超過傳教士的數目(否則不安全, 傳教士有可能被野人吃掉)。即求解傳教士和野人從左岸全部擺渡到右岸的過程中, 任何時刻滿足m(傳教士數)≥c(野人數)和m+c≤k的擺渡方案。
我們此處舉例 , 只討論n為3、k為2的乘渡問題, 這樣傳教士和野人問題的描述就具體為如下:
三個傳教士與三個野人來到河邊, 有一條船可供一人或兩人乘渡, 問題是如何用這條船渡河才能使得河的任一岸上野人的數目總不超過傳教士的數目(當然, 如果某一岸上只有野人而沒有傳教士是允許的)。
我們用乙個三元組(m c b)來表示河岸上的狀態, 其中m、c分別代表某一岸上傳教士與野人的數目, b=1表示船在這一岸, b=0則表示船不在。
設n=3, k=2, 則給定的問題可用下圖表示, 圖中l和r表示左岸和右岸, b=1或0分別表示有船或無船。
約束條件是: 兩岸上m≥c, 船上m+c≤2。
我們採用產生式系統來解決這一問題。由於傳教士與野人的總數目是一常數, 所以只要表示出河的某一岸上的情況就可以了, 為方便起見, 我們選擇傳教士與野人開始所在的岸為所要表示的岸, 並稱其為左岸, 另一岸稱為右岸。但顯然僅用描述左岸的三元組描述就足以表示出整個情況, 因此必須十分重視選擇較好的問題表示法。以後的討論還可以看到高效率的問題求解過程與控制策略有關, 合適的控制策略可縮小狀態空間的搜尋範圍, 提高求解的效率。因而問題的初始狀態是(3 3 1), 目標狀態是(0 0 0)。
(1) 綜合資料庫: 用三元組表示, 即 (ml, cl, bl), 其中0≤ml, cl≤3, bl∈
此時問題述簡化為 (3, 3, 1)® (0, 0, 0)
n=3的m-c問題, 狀態空間的總狀態數為4×4×2=32, 根據約束條件的要求, 可以看出只有20個合法狀態。再進一步分析後, 又發現有4個合法狀態實際上是不可能達到的。因此實際的問題空間僅由16個狀態構成。下表列出分析的結果:
(ml, cl, bl) (ml, cl, bl)
(0 0 1)達不到 (0 0 0)
(0 1 1) (0 1 0)
(0 2 1) (0 2 0)
(0 3 1) (0 3 0)達不到
(1 0 1)不合法 (1 0 0)不合法
(1 1 1) (1 1 0)
(1 2 1)不合法 (1 2 0)不合法
(1 3 1)不合法 (1 3 0)不合法
(2 0 1)不合法 (2 0 0)不合法
(2 1 1)不合法 (2 1 0)不合法
(2 2 1) (2 2 0)
(2 3 1)不合法 (2 3 0)不合法
(3 0 1)達不到 (3 0 0)
(3 1 1) (3 1 0)
(3 2 1) (3 2 0)
(3 3 1) (3 3 0)達不到
(2) 規則集合: 由擺渡操作組成。該問題主要有兩種操作: pmc操作(規定為從左岸划向右岸)和qmc操作(從右岸划向左岸)。每次擺渡操作, 船上人數有五種組合, 因而組成有10條規則的集合。下面定義的規則前5條為pmc操作(從左岸划向右岸), 後5條為qmc操作(從右岸划向左岸)。
if (ml, cl, bl=1) then (ml-1, cl, bl-1); (p10操作)
if (ml, cl, bl=1) then (ml, cl-1, bl-1); (p01操作)
if (ml, cl, bl=1) then (ml-1, cl-1, bl-1); (p11操作)
if (ml, cl, bl=1) then (ml-2, cl, bl-1); (p20操作)
if (ml, cl, bl=1) then (ml, cl-2, bl-1); (p02操作)
if (ml, cl, bl=0) then (ml+1, cl, bl+1); (q10操作)
if (ml, cl, bl=0) then (ml, cl+1, bl+1); (q01操作)
if (ml, cl, bl=0) then (ml+1, cl+1, bl+1); (q11操作)
if (ml, cl, bl=0) then (ml+2, cl, bl+1); (q20操作)
if (ml, cl, bl=0) then (ml, cl+2, bl+1); (q02操作)
(3) 初始和目標狀態: 即(3, 3, 1)和(0, 0, 0)。和八數碼遊戲的問題一樣, 建立了產生式系統描述之後, 就可以通過控制策略, 對狀態空間進行搜尋, 求得乙個擺渡操作序列, 使其實現目標狀態。
在討論用產生式系統求解問題時, 有時引入狀態空間圖的概念很有幫助。狀態空間圖是乙個有向圖, 其節點可表示問題的各種狀態(綜合資料庫), 節點之間的弧線代表一些操作(產生式規則), 它們可把一種狀態導向另一種狀態。這樣建立起來的狀態空間圖, 描述了問題所有可能出現的狀態及狀態和操作之間的關係, 因而可以較直觀地看出問題的解路徑及其性質。實際上只有問題空間規模較小的問題才可能作出狀態空間圖, 例如n=3的m-c問題,的其狀態空間圖如下圖所示, 此時採用的控制策略為順序選取規則。由於每個擺渡操作都有對應的逆操作, 即pmc對應qmc, 所以該圖也可表示成具有雙向弧的形式。
從狀態空間圖看出解序列相當之多, 但最短解序列只有4個, 例如
(p11、q10、p02、q01、p20、q11、p20、q01、p02、q01、p02)、
(p11、q10、p02、q01、p02、q11、p20、q01、p02、q10、p11)、
(p02、q01、p02、q01、p20、q11、p20、q01、p02、q01、p02)、
(p02、q01、p02、q01、p20、q11、p20、q01、p02、q10、p11),
均由11次擺渡操作構成。若給定其中任意兩個狀態分別作為初始和目標狀態, 就立即可找出對應的解序列來。在一般情況下, 求解過程就是對狀態空間搜尋出一條解路徑的過程。
以上這個例子說明了建立產生式系統描述的過程, 這也就是所謂問題的表示。對問題表示的好壞, 往往對求解過程的效率有很大影響。一種較好的表示法會簡化狀態空間和規則集表示, 例如八數碼問題中, 如用將牌移動來描述規則, 則8塊將牌就有32條的規則集, 顯然用空格走步來描述就簡單得多。又如m-c問題中, 用3×2的矩陣給出左、右岸的情況來表示一種狀態當然可以, 但顯然僅用描述左岸的三元組描述就足以表示出整個情況。
如果我們用micro-prolog的******語法來進行程式設計以實現求解乘渡的方案, 則根據你給出的詢問是which(或all)還是is能給出全部擺渡方案或乙個擺渡方案。下面的程式由於m-c關係的第乙個語句用了回溯控制「/」, 所以實際上只能得出乙個乘渡方案。
下面我們進行程式設計:
我們把滿足條件的狀態稱為安全狀態, 首先要定義出安全狀態, 通過對問題的分析, 不難得出只有滿足以下條件之一的狀態才是安全的(以左岸為例):
1. 傳教士與野人的數目相等;
2. 傳教士都在左岸;
3. 傳教士都不在左岸。
safe關係的三個句子分別定義了這三種不同的情況, 其中safe的第乙個變元表示傳教士的數目, 第二個變元表示野人的數目。
從乙個狀態到另一狀態的轉換, 通過關係rule來完成, 它有兩個句子, 分別描述了從左岸到右岸和從右岸到左岸的狀態轉換。rule的兩個變元都是三元組, 第乙個三元組表示當前狀態, 第二個三元組是得到的下乙個滿足條件的狀態。
關係m-c通過呼叫rule來求解出傳教士與野人的過河方案, 它有四個變元, 第乙個變元是當前狀態, 呼叫時用初始狀態代入, 第二個變元是目標狀態, 第三個變元是乙個中間變數, 它以表的形式記錄到目前為止所達到的狀態, 呼叫的初始值是只含初始狀態乙個元素的表, 第四個變元也是乙個表, 求解結束時, 它以逆序形式得到解的路徑。
傳教士野人過河問題
這個問題是人工智慧中經典的搜尋問題,下面用深度優先搜尋演算法來解這個題,示例 如下 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人乘渡。問傳教士為了安全起見,應如何規劃擺渡方案,...