传教士与野人过河问题文档格式.docx
《传教士与野人过河问题文档格式.docx》由会员分享,可在线阅读,更多相关《传教士与野人过河问题文档格式.docx(16页珍藏版)》请在冰豆网上搜索。
![传教士与野人过河问题文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/25/1a63fe07-4cc9-45b2-b504-f9445489fc3c/1a63fe07-4cc9-45b2-b504-f9445489fc3c1.gif)
对应右岸的传教士数为3—m;
左岸的食人者数为c,则有c={0,1,2,3};
对应右岸食人者数为3—c;
左岸船数为b,故又有b={0,1};
右岸的船数为1-b。
(2)确定状态组,分别列出初始状态集和目标状态集。
问题的状态可以用一个三元数组来描述,以左岸的状态来标记,即右岸的状态可以不必标出。
Sk=(m,c,b)
初始状态只有一个:
S0=(3,3,1),初始状态表示全部成员在河的的左岸;
目标状态也只有一个:
Sg=(0,0,0),表示全部成员从河的左岸全部渡河完毕。
(3)定义并确定操作集。
仍然以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij操作。
其中,第一下标i表示船载的传教士数,第二下标j表示船载的食人者数;
同理,从右岸将船划回左岸称之为Qij操作,下标的定义同前。
则共有10种操作,操作集为
F={P01,P10,P11,P02,P20,Q01,Q10,Q11,Q02,Q20}
(4)估计全部的状态空间数,并尽可能列出全部的状态空间或予以描述。
在这个问题世界中,S0={3,3,1}为初始状态,S31=Sg=(0,0,0)为目标状态。
全部的可能状态共有32个,如表6—1所示。
表6—1传教士和食人者问题的全部可能状态
状态
m,c,b
m,c,b
S0
3,3,1
S8
1,3,1
S16
3,3,0
S24
1,3,0
S1
3,2,1
S9
1,2,1
S17
3,2,0
S25
1,2,0
S2
3,1,1
S10
1,1,1
S18
3,1,0
S26
1,1,0
S3
3,0,1
S11
1,0,1
S19
3,0,0
S27
1,0,0
S4
2,3,1
S12
0,3,1
S20
2,3,0
S28
0,3,0
S5
2,2,1
S13
0,2,1
S21
2,2,0
S29
0,2,0
S6
2,1,1
S14
0,1,1
S22
2,1,0
S30
0,1,0
S7
2,0,1
S15
0,0,1
S23
2,0,0
S31
0,0,0
值得注意的是按照题目规定的条件,我们应该划去不合法的状态,这样可以加快搜索求解的效率。
例如,首先可以划去岸边食人者数目超过传教士的情况,即S4、S8、S9、S20、S24、S25等6种状态是不合法的;
其次,应该划去右岸边食人者数目超过修道士的情况,即S6、S7、S11、S22、S23、S27等情况;
余下20种合法状态中,又有4种是不可能出现的状态;
S15和S16不可能出现,因为船不可能停靠在无人的岸边;
S3不可能出现,因为传教士不可能在数量占优势的食人者眼皮底下把船安全地划回来;
还应该划去S28,因为传教士也不可能在数量占优势的食人者眼皮底下把船安全地划向对岸。
可见,在状态空间中,真正符合题目规定条件的只有16个合理状态。
(5)当状态数量不是很大时,按问题的有序元组画出状态空间图,依照状态空间图搜索求解。
根据上述分析,共有16个合法状态和允许的操作,可以划出传教士和食人者问题的状态空间图,如图6—4所示。
图6—4传教士和食人者问题的状态空间
如图6—4所示,由于划船操作是可逆的,所以图中状态节点间用双向箭头连接,箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
这样,任何一条从S0到达S31的路径都是该问题的解。
这样,通过运用状态空间表示法就解决了传教士和食人者问题的求解。
源代码:
#include<
stdio.h>
stdlib.h>
ctype.h>
#definemaxloop100/*最大层数,对于不同的扩展方法自动调整取值*/
#definepristnum3/*初始化时设定有3个野人3个传教士,实际可以改动*/
#defineslavenum3
structSPQ
{intsr,pr;
/*船运行一个来回后河右岸的野人、传教士的人数*/
intsl,pl;
/*船运行一个来回后河左岸的野人、传教士的人数*/
intssr,spr;
/*回来(由左向右时)船上的人数*/
intsst,spt;
/*去时(由右向左时)船上的人数*/
intloop;
/*本结点所在的层数*/
structSPQ*upnode,*nextnode;
/*本结点的父结点和同层的下一个结点的地址*/
}spq;
intloopnum;
/*记录总的扩展次数*/
intopenednum;
/*记录已扩展节点个数*/
intunopenednum;
/*记录待扩展节点个数*/
intresultnum;
structSPQ*opened;
structSPQ*oend;
structSPQ*unopened;
structSPQ*uend;
structSPQ*result;
voidinitiate();
voidreleasemem();
voidshowresult();
voidaddtoopened(structSPQ*ntx);
intsearch();
voidgoon();
intstretch(structSPQ*ntx);
voidrecorder();
voidaddtoopened(structSPQ*ntx)/*扩展节点*/
{
unopened=unopened->
nextnode;
unopenednum--;
if(openednum==0)
oend=opened=ntx;
oend->
nextnode=ntx;
oend=ntx;
openednum++;
}
voidrecorder()
inti,loop;
structSPQ*newnode;
structSPQ*ntx;
loop=oend->
loop;
ntx=oend;
resultnum=0;
for(i=0;
i<
=loop;
i++)
newnode=(structSPQ*)malloc(sizeof(spq));
if(newnode==NULL)
printf("
\n内存不够!
\n"
);
exit(0);
newnode->
sr=ntx->
sr;
pr=ntx->
pr;
sl=ntx->
sl;
pl=ntx->
pl;
sst=ntx->
sst;
spt=ntx->
spt;
ssr=ntx->
ssr;
spr=ntx->
spr;
nextnode=NULL;
ntx=ntx->
upnode;
if(i==0)
result=newnode;
nextnode=result;
resultnum++;
voidreleasemem()
inti;
structSPQ*nodefree;
for(i=1;
openednum;
nodefree=opened;
opened=opened->
free(nodefree);
for(i=0;
unopenednum;
nodefree=unopened;
voidshowresult()/*显示*/
intfsr,fpr;
/*在右岸上的人数*/
intfsl,fpl;
/*在左岸上的人数*/
%d个传教士"
result->
pr);
%d个野人"
sr);
pl);
sl);
resultnum;
nodefree=result;
result=result->
\n\n\t左岸人数船上人数及方向右岸人数\n"
第%d轮\n"
i);
fpl=result->
pl-result->
spt+result->
fpr=result->
pr-result->
fsl=result->
sl-result->
sst+result->
fsr=result->
sr-result->
传教士%8d%8d\t<
-\t%8d\n"
fpl,result->
spt,fpr);
野人%8d%8d\t<
fsl,result->
sst,fsr);
传教士%8d%8d\t->
\t%8d\n"
pl,result->
spr,result->
spr);
野人%8d%8d\t->
sl,result->
ssr,result->
ssr);
\n全体传教士和野人全部到达对岸"
free(result);
voidgoon()/*循环操作选择*/
charchoice;
for(;
;
)
是否继续?
(Y/N)\n"
scanf("
%s"
&
choice);
choice=toupper(choice);
if(choice=='
Y'
)break;
N'
)exit(0);
}
intmain()
{
intflag;
/*标记扩展是否成功*/
for(;
;
)
initiate();
flag=search();
if(flag==1)
recorder();
releasemem();
showresult();
goon();
else
无法找到符合条件的解"
}
system("
pause"
return0;
voidinitiate()
intx;
uend=unopened=(structSPQ*)malloc(sizeof(spq));
if(uend==NULL)
unopenednum=1;
openednum=0;
unopened->
upnode=unopened;
/*保存父结点的地址以成链表*/
nextnode=unopened;
sr=slavenum;
pr=pristnum;
sl=0;
pl=0;
sst=0;
spt=0;
ssr=0;
spr=0;
loop=0;
*********************************************************************\n"
题目:
设有n个传教士和m个野人来到河边,打算乘一只船从右岸到左岸去。
该船的负载能力为两人。
在任何时候,如果野人人数超过传教士人数,野人\n"
就会把传教士吃掉。
他们怎样才能用这条船安全的把所有人都渡过河去\n"
*********************************************************************"
\n默认的n、m值皆为3\n"
\n是否修改?
(Y/N)"
scanf("
&
\n请输入传教士人数"
%d"
x);
if(x>
0)
pr=x;
break;
elseprintf("
\n输入值应大于0!
\n请重新输入"
\n请输入野人人数"
sr=x;
intsearch()
/*提供将要扩展的结点的指针*/
ntx=unopened;
/*从待扩展链表中提取最前面的一个*/
if(ntx->
loop==maxloop)
return0;
addtoopened(ntx);
/*将ntx加入已扩展链表,并将这个节点从待扩展链表中去掉*/
flag=stretch(ntx);
/*对ntx进行扩展,返回-1,0,1*/
return1;
intstretch(structSPQ*ntx)
intsst,spt;
/*出发时在船上的人数*/
intssr,spr;
/*返回时船上的人数*/
for(sst=0;
sst<
=2;
sst++)/*讨论不同的可能性并判断是否符合条件*/
fsr=ntx->
fpr=ntx->
fsl=ntx->
fpl=ntx->
if((sst<
=fsr)&
&
((2-sst)<
=fpr))/*满足人数限制*/
spt=2-sst;
fsr=fsr-sst;
fpr=fpr-spt;
if((fpr==0)&
(fsr==0))/*搜索成功*/
upnode=ntx;
sr=0;
pr=0;
sl=opened->
pl=opened->
sst=sst;
spt=spt;
loop=ntx->
loop+1;
nextnode=newnode;
oend=newnode;
elseif((fpr-fsr)*fpr>
=0)/*判断是否满足传教士人数必须大于或等于野人人数*/
fsl=fsl+sst;
fpl=fpl+spt;
for(ssr=0;
ssr<
=1;
ssr++)/*返回*/
intffsl,ffpl;
if((ssr<
=fsl)&
((1-ssr)<
=fpl))
spr=1-ssr;
ffsl=fsl-ssr;
ffpl=fpl-spr;
if((ffpl-ffsl)*ffpl>
=0)
{/*若符合条件则分配内存并付值*/
intffsr,ffpr;
ffsr=fsr+ssr;
ffpr=fpr+spr;
sr=ffsr;
pr=ffpr;
sl=ffsl;
pl=ffpl;
ssr=ssr;
spr=spr;
loop