CSDNBlog |我的主頁|聯系作者|聚合|登錄5篇文章::0個收藏夾::0個評論::0個引用通告。
文章
C++/Visual C++(RSS)
算法設計(RSS)
遊戲開發(RSS)
收集
相冊
保存在檔案中
2004年6月(4)
2004年4月(1)
野蠻過河問題的算法分析
野蠻過河問題的算法分析
野人過河問題屬於人工智能中的壹個經典問題。問題是這樣描述的:有三個牧師(有的翻譯成傳教士)和三個野人過河,只有壹條船可以坐兩個人。在河的兩邊或者船上,如果野人的數量大於祭司的數量,那麽祭司們就有危險了。妳能找到安全過河的方法嗎?
壹、算法分析
我們來看看問題的初始狀態和目標狀態,假設sum分為A銀行和B銀行:
初始狀態:嘉安,3野人,3牧師;
b岸,0野人,0牧師;
船停在A岸,船上0人;
目標狀態:阿安,0野人,0牧師;
b岸,3個野人,3個牧師;
船停在B岸,船上0人。
整個問題抽象為如何從初始狀態通過壹系列中間狀態到達目標狀態。問題狀態的改變是劃船過河造成的,所以合理的渡河操作就成了算子。根據題目要求,可以得到以下五種運算符(根據擺渡方向,也可以理解為10運算符):
杜1野人,杜1牧師,杜1野人1牧師,杜2野人,杜2牧師。
運營商已知後,剩下的核心問題就是搜索方法。本文采用深度優先搜索,通過FindNext(…)函數找出下壹次渡河操作的最佳操作。如果沒有找到,就會返回到它的父節點,看看是否還有其他的兄弟節點可以展開,然後用Process(…)函數遞歸調用FindNext(…),逐層向後展開。
搜索中使用的壹些規則如下:
1.輪渡優先規則:A岸壹次運送的人越多越好(即A岸運送的人越多),野人優先運送;
壹次二岸運送的人越少越好(即二岸運送的人越少越好),牧師優先運送;
2.最後壹個擺渡操作不能重復(與鏈表中的前壹個操作相比),以避免進入無限循環;
3.在任何時候,河兩岸的野人和牧師的數量分別大於等於0和小於等於3;
4.因為只找到最優解,所以當壹個運算符(目前優先級最高)滿足運算條件時,不搜索其兄弟節點,而是直接加載到鏈表中。
5.如果在展開節點A時沒有找到合適的子節點,則從鏈表中返回節點A的父節點B,從上次選擇的算子中找到優先級最高的算子繼續展開B..
二、基本數據結構
仔細閱讀問題,可以發現壹些必須要把握的基本東西,比如每壹個時刻河兩岸的野人牧師數量,船的狀態,整個問題的狀態。因此,我們定義了以下數據結構:
typedef struct _ riverside//Shore state類型
{
int wildMan//野人數量
教士之間;//牧師人數
}濱江;
Typedef struct _boat //船的狀態類型。
{
int wildMan//野人數量
教士之間;//牧師人數
}船;
Typedef struct _question //整個問題狀態
{
濱江RIVERSIDE 1;//嘉安
濱江河畔2;//B銀行
int端;//船的位置是A岸-1,b岸1。
舟舟;//船的狀態
_ question * pPrev//指向上壹個輪渡操作
_ question * pNext//指向下壹個輪渡操作。
}問題;
使用QUESTION聲明壹個基本鏈表。
三、程序流程和具體設計
本文只求最優解。據我所知,這個問題有三種解決方法。如果妳真的想搞清楚這三個解決方案,_,妳得加強鏈表的操作,比如自己寫壹個動態鏈表類,順便完成壹些初始化工作,估計會更順手。
下面給出了壹些關鍵步驟:
//主函數
int main()
{
//初始化
QUESTION* pHead =新問題;
pHead-& gt;river side 1 . wild man = 3;
pHead-& gt;river side 1 . churchman = 3;
pHead-& gt;river side 2 . wild man = 0;
pHead-& gt;river side 2 . church man = 0;
pHead-& gt;side =-1;//船在a岸。
pHead-& gt;pPrev = NULL
pHead-& gt;pNext = NULL
pHead-& gt;boat . wild man = 0;
pHead-& gt;boat . churchman = 0;
if(進程(pHead))
{
//...遍歷鏈表並輸出結果。
}
cout & lt& lt“渡河成功。”;
}
其他
cout & lt& lt“我們怎麽過河?郁悶!”& lt& ltendl
//回收內存空間
while (pHead)
{
QUESTION * pTemp = pHead-& gt;pNext
刪除pHead
pHead = pTemp
}
pHead = NULL
返回0;
}
//擺渡進程,遞歸調用函數FindNext(...)
布爾過程(問題*問題)
{
if (FindNext(pQuest))
{
QUESTION* pNew =新問題;
pNew-& gt;river side 1 . wild man = p quest-& gt;river side 1 . wild man+pQuest-& gt;boat . wild man *(p quest-& gt;側);
pNew-& gt;river side 1 . churchman = p quest-& gt;river side 1 . churchman+pQuest-& gt;boat . churchman *(p quest-& gt;側);
pNew-& gt;河邊2 . wild man = 3-pNew-& gt;river side 1 . wild man;
pNew-& gt;河邊2 . churchman = 3-pNew-& gt;river side 1 . churchman;
pNew-& gt;side =(-1)* p quest-& gt;側面;
pNew-& gt;pPrev = pQuest
pNew-& gt;pNext = NULL
pNew-& gt;boat . wild man = 0;
pNew-& gt;boat . churchman = 0;
pQuest-& gt;pNext = pNew
if(pNew-& gt;河邊2 .懷爾德曼= = 3 & amp& amppNew-& gt;河邊2 .教士==3)
返回TRUE//完成
退貨流程(pNew);
}
其他
{
quest * PP rev = p quest-& gt;pPrev
if (pPrev == NULL)
返回FALSE//無解
刪除pQuest
pPrev-& gt;pNext = NULL
退貨流程(PP rev);//返回其父節點並重試。
}
返回TRUE
}
//判斷是否有下壹個交叉操作,即根據比較算子找出能靠近目標節點的操作。
//運算符***5: 1野/1牧/1野1牧/2野/2牧。
BOOL FindNext(問題*問題)
{
//基本規則
//渡船優先:壹是岸上運送人多,野人優先;人少的b岸運優先,牧師優先。
靜態船boatState[5];// 5個運算符
if(pQuest-& gt;side == -1)
{
船州[0]。wild man = 2;
船州[0]。churchMan = 0;
boatState[1]。wild man = 1;
boatState[1]。churchMan = 1;
船州[2]。wild man = 0;
船州[2]。churchMan = 2;
船州[3]。wild man = 1;
船州[3]。churchMan = 0;
船州[4]。wild man = 0;
船州[4]。churchMan = 1;
}
其他
{
船州[0]。wild man = 0;
船州[0]。churchMan = 1;
boatState[1]。wild man = 1;
boatState[1]。churchMan = 0;
船州[2]。wild man = 0;
船州[2]。churchMan = 2;
船州[3]。wild man = 1;
船州[3]。churchMan = 1;
船州[4]。wild man = 2;
船州[4]。churchMan = 0;
}
int I;//用於控制運算符
if(pQuest-& gt;boat.wildMan = = 0 & amp& amppQuest-& gt;船。丘吉爾= = 0)//初始狀態,第壹次過河的時候。
I = 0;//運算符1
其他
{
for(I = 0;我& lt5;I++) //擴展同壹個節點時,已經使用的運算符不再使用,優先使用。
if(pQuest-& gt;boat.wildMan == boatState[i]。懷爾德曼& amp& amppQuest-& gt;boat.churchMan == boatState[i]。教士)
打破;
i++;
}
如果(我& lt5)
{
int j;
for(j = I;j & lt5;j++)
{
int nwildman 1 = p quest-& gt;river side 1 . wild man+boat state[j]。wild man * pQuest-& gt;側面;
int nchurchman 1 = p quest->;河邊1 .教會人士+船州[j]。churchMan * pQuest-& gt;側面;
int nwildman 2 = 3-nwildman 1;
int nchurchman 2 = 3-nchurchman 1;
//判斷這個操作的安全性,即牧師人數> =野人或牧師人數為0。
if((nwildman 1 & lt;= nchurchman 1 | | nchurchman 1 = = 0)& amp;& amp
(nWildMan2 & lt= nchurchman 2 | | nchurchman 2 = = 0)& amp;& amp
nwildman 1 & gt;= 0 & amp& ampnchurchman 1 & gt;= 0 & amp& ampnWildMan2 & gt= 0 & amp& ampnChurchMan2 >= 0)
{
//這個操作是否重復上壹個操作,註意方向不同。
if(pQuest-& gt;pPrev!=空)
{
if(pQuest-& gt;pPrev-& gt;boat.wildMan == boatState[j]。懷爾德曼& amp& amp
pQuest-& gt;pPrev-& gt;boat.churchMan == boatState[j]。教士)
繼續;
}
打破;//此操作可行,並推導出循環,只找到當前最優節點。
}
}
if(j & lt;5)
{
pQuest-& gt;boat.wildMan = boatState[j]。懷爾德曼;
pQuest-& gt;boat.churchMan = boatState[j]。教士;
返回TRUE
}
}
返回FALSE
}
Trackback: /TrackBack.aspx?PostId=21630
【點擊此處收藏本文】發表於2004年4月7日下午2:18。
無可奉告。
評論
名稱:
請輸入您的姓名。
網址:
驗證碼
評論
請輸入評論。
記得我嗎?
-
網站介紹-廣告服務-網站地圖-幫助信息-聯系信息-英語-問題報告
CSDN北京安百裏美達美數碼科技有限公司版權所有北京ICP證字第020026號CSDN
2000-04,CSDN.NET,保留所有權利
-
版權?paddy102由。文本