傳教士和野人過河(經典MC問題)


     這個問題本來是《人工智能技術導論》第三章的課后題,今天上午考試正巧考到了這道題,要我們畫狀態轉換圖,我之前思考過一點,所以寫出的狀態表示應該沒有問題,但這些狀態太多了.......,十來種狀態直接給我干懵逼了,兩個小時的考試,差不多得有一個小時在推導狀態轉換關系,最后整個考場就剩下我和譚神兩個人了,這里寫下博客,整理一下這個問題。

網上搜索發現這個博主的做法和我的做法大致一樣的,他最后給出了C++的實現方式。這篇博客狀態分析部分就主要參考https://www.cnblogs.com/guanghe/p/5485800.html

后面再附上PROLOG程序的解決方案。

一、問題重述  

在河的左岸有N個傳教士、N個野人和一條船,傳教士們想用這條船把所有人都運過河去,但有以下條件限制:

(1)修道士和野人都會划船,但船每次最多只能運K個人;
(2)在任何岸邊野人數目都不能超過修道士,否則修道士會被野人吃掉。

假定野人會服從任何一種過河安排,請規划出一個確保修道士安全過河的計划。

二、問題分析 

1、約束條件

  ① M≧C 任何時刻兩岸、船上都必須滿足傳教士人數不少於野人數(M=0時除外,既沒有傳教士) 
  ② M+C≦K 船上人數限制在K以內

2、求解 

 傳教士與野人全部安全渡到對岸的解決方案

三、狀態表示

    設N=3,K=2(三個M和三個C,每次渡河二人以下)     
     L:左岸,R:右岸, 
     B:是否有船(0:無船,1:有船) 

    定義:用三元組(ML,CL,BL)表示左岸狀態,其中:
    0≦ML,CL≦3,BL∈{0,1}
    如:(0,3,1)表示左岸有三個野人,船在左岸。
    從(3,3,1)到(0,0,0)的狀態轉換
    狀態空間:32 種狀態,其中:
    12種不合理狀態:如(1,0,1)說明右岸有2個M,3個C;
    4種不可能狀態:如(3,3,0)說明所有M和C都在左岸,而船在右岸
   

 ∴可用的狀態共16種,組成合理的狀態空間 
    圖片

        狀態空間具體描述
       圖片

四、操作集

    定義:Pmc操作:從左岸划向右岸

               Qmc操作:從右岸划向左岸

 船上人數組合(m,c)共5種(1,0),(1,1),(2,0),(0,1),(0,2)

    ∵每一種船上的人數組合同時對應P,Q二種操作

    ∴系統共有5×2=10種操作(規則)

 如:P10:if (ML,CL,BL=1) then (ML-1,CL,BL-1)

     如果船在左岸,那么一個傳教士划船到右岸

     Q01:if (ML,CL,BL=0) then (ML,CL+1,BL+1)

     如果船在右岸,那么一個野人划船回到左岸

 總共有10種操作

  F={P10,P20, P11, P01, P02, Q 10, Q 20, Q 11, Q 01, Q 02} 
  P10   if( ML ,CL , BL=1 )   then ( ML–1 , CL , BL–1 )
  P01   if( ML ,CL , BL=1 )   then ( ML , CL–1 , BL–1 )
  P11   if( ML ,CL , BL=1 )   then ( ML–1 , CL–1 ,BL –1 )
  P20   if( ML ,CL , BL=1 )   then ( ML–2 , CL , BL–1 )
  P02   if( ML ,CL , BL=1 )   then ( ML , CL–2 , BL–1 )
  Q10   if( ML ,CL , BL=0 )   then ( ML+1 , CL ,BL+1 )
  Q01   if( ML ,CL , BL=0 )   then ( ML , CL+1 , BL+1 )
  Q11   if( ML ,CL , BL=0 )   then ( ML+1 , CL +1,BL +1 )
  Q20   if( ML ,CL , BL=0 )   then ( ML+2 , CL +2,BL +1 ) 
  Q02   if( ML ,CL , BL=0 )   then ( ML , CL +2, BL+1 ) 

控制策略
    最短路徑有4條,由11次操作構成。

(P11、Q10、P02、Q01、P20、Q11、P20、Q01、P02、Q01、P02)
(P11、Q10、P02、Q01、P20、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)  

五、狀態空間圖

     狀態空間圖是一個有向圖,圖中的節點代表狀態,節點之間的連線代表操作,箭頭代表狀態的轉換方向。
 圖片

圖片

 

 

 

六、PROLOG程序設計

這里給出參考的鏈接https://github.com/kylynf/PrologMC

% start([3,3,near]).
% goal([0,0,far]).

change(near,far).
change(far,near).

% boat must be in valid location
% valid number of missionaries and cannibals on each shore
% no more than three and no fewer than zero
valid([Missionaries,Cannibals,near]) :-
    Missionaries=<3,
    Cannibals=<3,
    Missionaries>=0,
    Cannibals>=0.

valid([Missionaries,Cannibals,far]) :-
    Missionaries=<3,
    Cannibals=<3,
    Missionaries>=0,
    Cannibals>=0.

% oneEq(X,X,_).
% oneEq(X,_,X).

% no missionaries are in danger of being eaten
safe([Missionaries,Cannibals,_]) :-
    % oneEq(3,3,_),oneEq(2,2,_),oneEq(1,1,_),oneEq(0,0,_),oneEq(0,1,_),oneEq(0,2,_),oneEq(0,3,_),oneEq(3,0,_),oneEq(3,1,_),oneEq(3,2,_).
    % (Missionaries=<Cannibals ; Cannibals=0),
    (Missionaries>=Cannibals ; Missionaries=0),
    FarMis is 3 - Missionaries, FarCan is 3 - Cannibals,
    (FarMis >= FarCan; FarMis=0).

% onemissionary
move([M1,C1,B1],onemissionary,[M2,C2,B2]) :-
    change(B1, B2),
    C1 = C2,
    (B1=near -> DM is M1-1 ; DM is M1+1),
    M2 = DM.

%twomissionaries
move([Missionaries1,Cannibals1,Boat1],twomissionaries,[Missionaries2,Cannibals2,Boat2]) :-
    change(Boat1,Boat2),
    Cannibals1 = Cannibals2,
    (Boat1=near -> DummyMissionary is Missionaries1-2 ; DummyMissionary is Missionaries1+2),
    Missionaries2 = DummyMissionary.

%onecannibal
move([Missionaries1,Cannibals1,Boat1],onecannibal,[Missionaries2,Cannibals2,Boat2]) :-
    % boat1==near,boat2==far,Cannibals2 is Cannibals1 - 1;
    % boat1==far,boat2==near,Cannibals2 is Cannibals1 + 1.
    change(Boat1,Boat2),
    Missionaries1 = Missionaries2,
    (Boat1=near -> DummyCannibal is Cannibals1-1 ; DummyCannibal is Cannibals1+1),
    Cannibals2 = DummyCannibal.

%twocannibal
move([Missionaries1,Cannibals1,Boat1],twocannibals,[Missionaries2,Cannibals2,Boat2]) :-
    change(Boat1, Boat2),
    Missionaries1 = Missionaries2,
    (Boat1=near -> DummyCannibal is Cannibals1-2 ; DummyCannibal is Cannibals1+2),
    Cannibals2 = DummyCannibal.

% oneofeach
move([Missionaries1,Cannibals1,Boat1],oneofeach,[Missionaries2,Cannibals2,Boat2]) :-
    change(Boat1,Boat2),
    (Boat1=near -> DummyCannibal is Cannibals1-1, DummyMissionary is Missionaries1-1 ; DummyCannibal is Cannibals1+1, DummyMissionary is Missionaries1+1),
    Cannibals2 = DummyCannibal,
    Missionaries2 = DummyMissionary.

solution([0,0,far],[]).
solution(State,[Move|Rest]) :-
    move(State,Move,NextState),
    valid(NextState),
    safe(NextState),
    solution(NextState,Rest).

solve(X) :-
    length(X,11),
    solution([3,3,near],X).


免責聲明!

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



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