標籤:
題目:
有N個傳教士和N個野人要過河,現在有一條船隻能承載M個人,在任何時刻,如果有野人和傳教士在一起,必須要求傳教士的人數多於或等於野人的人數(包括船上和兩個岸邊)。
設M為傳教士的人數,C為野人的人數,當N=3, M=2時, 用狀態空間法求解此問題的過程如下:
(1)設定狀態變數並確定範圍
S、C = N,B = { 0 , 1} (1表示在岸邊),要求在船上S>=C且S+C <= M
初始狀態 目標狀態
(2)確定狀態組,分別列出初始狀態集和目標狀態集
用三元組來表示(S , C , B)這裡面都表示的是左岸狀態
其中0<=S , C <= 3 , B∈{ 0 , 1}
(3 , 3 , 1) (0 , 0 , 0)
初始狀態表示全部成員在河的的左岸, 目標狀態表示全部成員從河的左岸全部渡河完畢。
(3)定義並確定規則集合
仍然以河的左岸為基點來考慮,把船從左岸劃向右岸定義為Pij操作。其中,第一個下標i表示船載的傳教士人數,第二個下標j表示船載的野人人數。同理,從右岸將船劃回左岸稱之為Qij操作,下標的定義同前。 則共有10種操作,操作集為:
F={P10, P01,P11,P20,P02,Q10,Q01,Q11,Q20,Q02}
P10 if ( S , C , B=1 ) then ( S–1 , C , B –1 )
P01 if ( S , C , B=1 ) then ( S, C–1 , B –1 )
P11 if ( S , C , B=1 ) then ( S –1 , C–1 , B –1 )
P20 if ( S , C , B=1 ) then ( S –2 , C , B –1 )
P02 if ( S , C , B=1 ) then ( S, C–2 , B –1 )
Q10 if ( S , C , B=0 ) then ( S +1 , C , B+1 )
Q01 if ( S , C , B=0 ) then ( S, C+1 , B +1 )
Q11 if ( S , C , B=0 ) then ( S +1 , C +1, B +1 )
Q20 if ( S , C , B=0 ) then ( S +2 , C +2, B +1 )
Q02 if ( S , C, B=0 ) then ( S, C +2, B +1 )
(4)當狀態數量不是很大時,畫出合理的狀態空間圖(略)
用廣度優先的方法,求最少次數:
#include <cstdio>#include <iostream>#include <vector>#include <queue>#include <set>using namespace std;// N is the number of scholars/cannibals, M is the boat‘s capacityint N,M;class BoatState{public: int scholars; int cannibals;};class LeftRiverSideState{public: int scholars; int cannibals; bool isBoatOnStandby; int countTimes;};void createBoatState(vector<BoatState> &boatStates){ //i cannibals, j scholars. for(int i=0; i<=M; ++i) { for(int j=0; j<=M; ++j) { if(i+j>0 && i+j<=M && (i<=j||j==0)) { BoatState bState; bState.cannibals = i; bState.scholars = j; boatStates.push_back(bState); } } }}void changeState(LeftRiverSideState &lrsState, queue<LeftRiverSideState> &stateQueue, vector<BoatState> &boatStates){ int countTimes = lrsState.countTimes + 1; if(lrsState.isBoatOnStandby) { for(vector<BoatState>::iterator iter=boatStates.begin(); iter!=boatStates.end(); ++iter) { if(lrsState.cannibals >= iter->cannibals && lrsState.scholars >= iter->scholars) { LeftRiverSideState tmpState; tmpState.cannibals = lrsState.cannibals - iter->cannibals; tmpState.scholars = lrsState.scholars - iter->scholars; tmpState.isBoatOnStandby = false; tmpState.countTimes = countTimes; stateQueue.push(tmpState); } } } else { for(vector<BoatState>::iterator iter=boatStates.begin(); iter!=boatStates.end(); ++iter) { if((N-lrsState.cannibals) >= iter->cannibals && (N-lrsState.scholars) >= iter->scholars) { LeftRiverSideState tmpState; tmpState.cannibals = lrsState.cannibals + iter->cannibals; tmpState.scholars = lrsState.scholars + iter->scholars; tmpState.isBoatOnStandby = true; tmpState.countTimes = countTimes; stateQueue.push(tmpState); } } }}int calculateMinTimes(queue<LeftRiverSideState> &stateQueue, vector<BoatState> &boatStates){ vector<LeftRiverSideState> checkState; while(stateQueue.size() > 0) { LeftRiverSideState lrsState = stateQueue.front(); stateQueue.pop(); //end condition if(lrsState.cannibals==0 && lrsState.scholars==0 && lrsState.isBoatOnStandby == false) { return lrsState.countTimes; } //check left/right river side if( (lrsState.cannibals>lrsState.scholars && lrsState.scholars!=0) || (N-lrsState.cannibals>N-lrsState.scholars && N-lrsState.scholars!=0) ) { continue; } //check endless loop bool flag = false; for(vector<LeftRiverSideState>::iterator iter=checkState.begin(); iter!=checkState.end(); ++iter) { if(iter->cannibals==lrsState.cannibals && iter->isBoatOnStandby==lrsState.isBoatOnStandby && iter->scholars==lrsState.scholars) { flag = true; break; } } if(flag) { continue; } checkState.push_back(lrsState); changeState(lrsState, stateQueue, boatStates); } return -1;}int main(int argc, char** argv){ int tc, T; freopen("E:/sample_input.txt", "r", stdin); cin >> T; for(tc = 0; tc < T; tc++) { cin >> N >> M; vector<BoatState> boatStates; createBoatState(boatStates); LeftRiverSideState lrsState; lrsState.cannibals = N; lrsState.scholars = N; lrsState.countTimes = 0; lrsState.isBoatOnStandby = true; queue<LeftRiverSideState> stateQueue; stateQueue.push(lrsState); int ret = calculateMinTimes(stateQueue, boatStates); if(ret != -1) { cout << ret << endl; } else { cout << "impossible" <<endl; } } return 0;}
傳教士-野人問題