传教士与野人问题

2026/4/28 4:25:29

实验二 知识表示方法

状态空间法实验

1.实验目的

(1)了解知识表示相关技术;

(2)掌握问题规约法或者状态空间法的分析方法。 2.实验内容(2个实验内容可以选择1个实现)

(1)梵塔问题实验。熟悉和掌握问题规约法的原理、实质和规约过程;理解规约图的表示方法;

(2)状态空间法实验。从前有一条河,河的左岸有m个传教士、m个野人和一艘最多可乘n人的小船。约定左岸,右岸和船上或者没有传教士,或者野人数量少于传教士,否则野人会把传教士吃掉。搜索一条可使所有的野人和传教士安全渡到右岸的方案。 3.实验报告要求

(1)简述实验原理及方法,并请给出程序设计流程图。

有N个传教士和N个野人来到河边准备渡河,河岸有一条船,每次至多可供k人乘渡。问传教士为了安全起见,应如何规划摆渡方案,使得任何时刻,在河的两岸以及船上的野人数目总是不超过传教士的数目。即求解传教士和野人从左岸全部摆渡到右岸的过程中,任何时刻满足M(传教士数)≥C(野人数)和M+C≤K的摆渡方案。

由于传教士和野人数是一个常数,所以知道了一岸的情况,另一岸的情况也就知道了。因此为了简便起见,在描述问题时,只描述一岸--如左岸--的情况就可以了。另外,该问题我们最关心的是在摆渡过程中,两岸状态的变化情况,因此船上的情况并不需要直接表达出来。在一次摆渡过程中,船上究竟有几个传教士和野人,可以通过两个相连的状态简单得到。这样表达更简练,突出了问题的重点。

(ML,CL,BL),其中0≤ML,CL≤3,BL∈{0,1},其中ML表示在左岸的传教士人数,CL表示在左岸的野人数,BL=1表示船在左岸,BL=0表示船在右岸。则此时问题描述可以简化为: (N,N,1)→(0,0,0)

(2)源程序清单:

#include using namespace std; struct data {

int M; //传教士人数 int C; //野人数 int B; //船 };

data state[50]; //记录状态

int K,M,sum=0; //载重,人数,解的个数 data Right,Left;//左岸和右岸的状态

void setData(data& Data,int m,int c,int b)//设置两岸状态 {

Data.M=m; Data.C=c; Data.B=b; }

void Print(int depth) //输出状态序列 {

for(int i=0;i

cout<<\

cout<<\-1].B<<\ }

bool noCircle(int m,int c,int k) //看状态序列中是否有自环 {

bool flag=false;

for(int i=0;i

if((state[i].B==Right.B)&&(state[i].M==m)&&(state[i].C==c)) {

flag=true; break; }

if(flag)return false; return true; }

bool safe(int m,int c) //看过河方案是否合理 {

if((m+c)>0&&(m+c)<=K) {

if(Right.B==0&&(m>=c||m==0)&&(((Left.M-m)>=(Left.C-c))||Left.M==m)&&(((Right.M+m)>=(Right.C+c))||(Right.M+m)==0)&&(Left.M-m>=0)&&(Left.C-c>=0)&&(Right.M+m<=M)&&(Right.C+c<=M))return true;

if(Right.B==1&&(m>=c||m==0)&&((Left.M+m)>=(Left.C+c)||(Left.M+m)==0)&&((Right.M-m)>=(Right.C-c)||Right.M==m)&&(Left.M+m<=M)&&(Left.C+c<=M)&&(Right.M-m>=0)&&(Right.C-c>=0))return true; }

return false; }

void Find(int depth) //递归求解 {

if(Left.M==0&&Left.C==0) //出口 {

sum++;

Print(depth); } else

for(int i=0;i<=M;i++) {

for(int j=0;j<=M;j++) {

if((Left.B==1)&&safe(i,j)&&noCircle(Left.M-i,Left.C-j,depth)) {

setData(state[depth],Left.M-i,Left.C-j,0); //在左岸,递归并回溯

setData(Right,Right.M+i,Right.C+j,1); setData(Left,Left.M-i,Left.C-j,0); Find(depth+1);

setData(state[depth],0,0,0);

setData(Right,Right.M-i,Right.C-j,0); setData(Left,Left.M+i,Left.C+j,1); }

if((Left.B==0)&&safe(i,j)&&noCircle(Left.M+i,Left.C+j,depth)) {

setData(state[depth],Left.M+i,Left.C+j,1); //在右岸,递归并回溯

setData(Right,Right.M-i,Right.C-j,0); setData(Left,Left.M+i,Left.C+j,1); Find(depth+1);

setData(state[depth],0,0,0);

setData(Right,Right.M+i,Right.C+j,1); setData(Left,Left.M-i,Left.C-j,0); } } } }

int main() {

cout<<\请输入人数:\

cin>>M;

cout<<\请输入容量:\ cin>>K;

setData(state[0],M,M,1); //设置初始状态 setData(Left,M,M,1); setData(Right,0,0,0);

Find(1); //开始求解 if(sum==0)cout<<\ else cout<<\共有\个解\ return 0; }

(3)实验结果及分析。

由以上结果可知成功完成实验目的,仅展示一个较简单的结果,下面展示人数为5,容量为3的结果


传教士与野人问题.doc 将本文的Word文档下载到电脑
搜索更多关于: 传教士与野人问题 的文档
相关推荐
相关阅读
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 10

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219