admin 管理员组文章数量: 1087139
2023年12月24日发(作者:c语言原码和补码)
.
实验 传教士野人过河问题
37030602 王世婷
一、实验问题
传教士和食人者问题(The Missionaries and Cannibals Problem)。在河的左岸有3个传教士、1条船和3个食人者,传教士们想用这条船将所有的成员运过河去,但是受到以下条件的限制:(1)传教士和食人者都会划船,但船一次最多只能装运两个;(2)在任何岸边食人者数目都不得超过传教士,否则传教士就会遭遇危险:被食人者攻击甚至被吃掉。此外,假定食人者会服从任何一种过河安排,试规划出一个确保全部成员安全过河的计划。
二、解答步骤
(1) 设置状态变量并确定值域
M为传教士人数,C 为野人人数,B为船数,要求M>=C且M+C <= 3,L表示左岸,R表示右岸。
初始状态 目标状态
L R L R
M 3 0 M 0 3
C 3 0 C 0 3
B 1 0 B 0 1
(2) 确定状态组,分别列出初始状态集和目标状态集
用三元组来表示Sf:(ML , CL , BL)(均为左岸状态)
其中0ML3,0CL3,BL ∈{ 0 , 1}
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}
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) 当状态数量不是很大时,画出合理的状态空间图
图1 状态空间图
箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
三、算法设计
方法一: 树的遍历
根据规则由根(初始状态)扩展出整颗树,检测每个结点的“可扩展标记”,为“-1”的即目标结点。由目标结点上溯出路径。
见源程序1。
.
.
方法二:启发式搜索
构造启发式函数为:
6.01MLCL满足规则时
f-其它选择较大值的结点先扩展。
见源程序2。
四、实验结果
方法一的实验结果:
传教士野人过河问题
第1种方法:
第1次:左岸到右岸,传教士过去1人,野人过去1人
第2次:右岸到左岸,传教士过去1人,野人过去0人
第3次:左岸到右岸,传教士过去0人,野人过去2人
第4次:右岸到左岸,传教士过去0人,野人过去1人
第5次:左岸到右岸,传教士过去2人,野人过去0人
第6次:右岸到左岸,传教士过去1人,野人过去1人
第7次:左岸到右岸,传教士过去2人,野人过去0人
第8次:右岸到左岸,传教士过去0人,野人过去1人
第9次:左岸到右岸,传教士过去0人,野人过去2人
第10次:右岸到左岸,传教士过去0人,野人过去1人
第11次:左岸到右岸,传教士过去0人,野人过去2人
第2种方法:
第1次:左岸到右岸,传教士过去1人,野人过去1人
第2次:右岸到左岸,传教士过去1人,野人过去0人
第3次:左岸到右岸,传教士过去0人,野人过去2人
第4次:右岸到左岸,传教士过去0人,野人过去1人
第5次:左岸到右岸,传教士过去2人,野人过去0人
第6次:右岸到左岸,传教士过去1人,野人过去1人
第7次:左岸到右岸,传教士过去2人,野人过去0人
第8次:右岸到左岸,传教士过去0人,野人过去1人
第9次:左岸到右岸,传教士过去0人,野人过去2人
第10次:右岸到左岸,传教士过去1人,野人过去0人
第11次:左岸到右岸,传教士过去1人,野人过去1人
第3种方法:
第1次:左岸到右岸,传教士过去0人,野人过去2人
第2次:右岸到左岸,传教士过去0人,野人过去1人
第3次:左岸到右岸,传教士过去0人,野人过去2人
第4次:右岸到左岸,传教士过去0人,野人过去1人
第5次:左岸到右岸,传教士过去2人,野人过去0人
第6次:右岸到左岸,传教士过去1人,野人过去1人
.
.
第7次:左岸到右岸,传教士过去2人,野人过去0人
第8次:右岸到左岸,传教士过去0人,野人过去1人
第9次:左岸到右岸,传教士过去0人,野人过去2人
第10次:右岸到左岸,传教士过去0人,野人过去1人
第11次:左岸到右岸,传教士过去0人,野人过去2人
第4种方法:
第1次:左岸到右岸,传教士过去0人,野人过去2人
第2次:右岸到左岸,传教士过去0人,野人过去1人
第3次:左岸到右岸,传教士过去0人,野人过去2人
第4次:右岸到左岸,传教士过去0人,野人过去1人
第5次:左岸到右岸,传教士过去2人,野人过去0人
第6次:右岸到左岸,传教士过去1人,野人过去1人
第7次:左岸到右岸,传教士过去2人,野人过去0人
第8次:右岸到左岸,传教士过去0人,野人过去1人
第9次:左岸到右岸,传教士过去0人,野人过去2人
第10次:右岸到左岸,传教士过去1人,野人过去0人
第11次:左岸到右岸,传教士过去1人,野人过去1人
方法二的实验结果:
传教士野人过河问题
方法如下
第1次:左岸到右岸,传教士过去1人,野人过去1人 l:2r,2y r:1r,1y
第2次:右岸到左岸,传教士过去1人,野人过去0人 l:3r,2y r:0r,1y
第3次:左岸到右岸,传教士过去0人,野人过去2人 l:3r,0y r:0r,3y
第4次:右岸到左岸,传教士过去0人,野人过去1人 l:3r,1y r:0r,2y
第5次:左岸到右岸,传教士过去2人,野人过去0人 l:1r,1y r:2r,2y
第6次:右岸到左岸,传教士过去1人,野人过去1人 l:2r,2y r:1r,1y
第7次:左岸到右岸,传教士过去2人,野人过去0人 l:0r,2y r:3r,1y
第8次:右岸到左岸,传教士过去0人,野人过去1人 l:0r,3y r:3r,0y
第9次:左岸到右岸,传教士过去0人,野人过去2人 l:0r,1y r:3r,2y
第10次:右岸到左岸,传教士过去0人,野人过去1人 l:0r,2y r:3r,1y
第11次:左岸到右岸,传教士过去0人,野人过去2人 l:0r,0y r:3r,3y
问题结束
由结果可以看出,方法二的结果为方法一的第一种结果,两者具有一致性。
五、总结与教训:
最开始时采用的方法为:用向量A{X0,X1,X2,X3,X4,X5,X6}表示状态,其中X0~X2表示三个传教士的位置,X3~X5表示三个野人的位置,X6表示船的位置。0表示在河左岸,1表示已渡过了河,在河右岸。
设初始状态和目标状态分别为:
.
.
S:S0{0,0,0,0,0,0,0}
G:Sg{1,1,1,1,1,1,1}
但在描述规则时发现这样定义会造成规则麻烦、不清晰,原因在于此题并不关心是哪几个传教士和野人在船上,仅关心其人数,故没有必要将每个人都设置变量,分别将传教士、野人、船作为一类即可。
四、源代码
1. 源程序1:树的遍历
%野人和传教士过河问题
%date:2010/12/14
%author:wang shi ting
function [ ]=guohe()
clear all;
close all;
global n node;
n=2;
solveNum=1; %问题的解法
result=zeros(100,1);
node=zeros(300,5);
node(1,:)=[3,3,1,1,-1];%初始化
%1左岸传教士数 2左岸野人数 3船(1为左岸,0为右岸)
%4是否可扩展(1为可扩展) 5父节点号(-1表示无父节点,即为初始节点)
j=1;
% for j=1:n
while (1)
if j>n
break
end
if node(j,4)==1 %判断结点是否可扩展
if node(j,3)==1 %船在左岸
if ( (node(j,1)==0) || (node(j,1)==3) )&&(node(j,2)>=1)
forward(j,0,1);
end
if (node(j,1)==1 && node(j,2)==1 || node(j,1)==3 && node(j,2)==2)
forward(j,1,0);
end
if (node(j,1)>=1 && node(j,1)==node(j,2))
forward(j,1,1);
.
.
end
if (node(j,1)==0 || node(j,1)==3)&& node(j,2)>=2
forward(j,0,2);
end
if (node(j,1)==2 && node(j,2)==2 || node(j,1)==3 && node(j,2)==1)
forward(j,2,0);
end
elseif node(j,3)==0%船在右岸
if ( (node(j,1)==0) || (node(j,1)==3) )&&(node(j,2)<=2)
afterward(j,0,1);
end
if (node(j,1)==2 && node(j,2)==2 || node(j,1)==0 && node(j,2)==1)
afterward(j,1,0);
end
if (node(j,1)<=2 && node(j,1)==node(j,2))
afterward(j,1,1);
end
if (node(j,1)==0 || node(j,1)==3)&& node(j,2)<=1
afterward(j,0,2);
end
if (node(j,1)==1 && node(j,2)==1 || node(j,1)==0 && node(j,2)==2)
afterward(j,2,0);
end
end
end
j=j+1;
end
fprintf('传教士野人过河问题n');
for t=1:n
j=1;
k=t;
StepNum=1;
if node(k,4)==-1
while (k~=-1)
result(j)=k;
k=node(k,5);
j=j+1;
end
j=j-1;
fprintf('第%d种方法:n',solveNum);
while j>1
BoatPriNum=node(result(j),1)-node(result(j-1),1);
BoatWildNum=node(result(j),2)-node(result(j-1),2);
if node(result(j),3)==1
.
.
fprintf('第%d次:左岸到右岸,传教士过去%d人,野人过去%d人n',...
StepNum,abs(BoatPriNum),abs(BoatWildNum));
StepNum=StepNum+1;
end
if node(result(j),3)==0
fprintf('第%d次:右岸到左岸,传教士过去%d人,野人过去%d人n',...
StepNum,abs(BoatPriNum),abs(BoatWildNum));
StepNum=StepNum+1;
end
j=j-1;
end
pause(0.2);
fprintf('n');
solveNum=solveNum+1;
end
end
fprintf('问题结束');
%%
%从左岸到右岸,船上传教士x个,野人y个
function []=forward(z,x,y)
global n;
global node;
node(n,1)=node(z,1)-x;
node(n,2)=node(z,2)-y;
node(n,3)=0;
r=search(z);
if(~r)
return
end
node(z,4)=0;
node(n,4)=1;
node(n,5)=z;
s=destination();
if s
node(n,4)=-1;
end
n=n+1;
%%
%%从右岸到左岸,船上传教士x个,野人y个
.
.
function []=afterward(z,x,y)
global n;
global node;
node(n,1)=node(z,1)+x;
node(n,2)=node(z,2)+y;
node(n,3)=1;
r=search(z);
if(~r)
return
end
node(z,4)=0;
node(n,4)=1;
node(n,5)=z;
s=destination();
if s
node(n,4)=-1;
end
n=n+1;
%%
function r=search(x)
global n node;
i=x;
while node(i,5)~=-1
if node(i,1)==node(n,1) && node(i,2)==node(n,2) && node(i,3)==node(n,3)
r=0;
return
end
i=node(i,5);
end
%跟初始节点比较
if node(i,1)==node(n,1) && node(i,2)==node(n,2) && node(i,3)==node(n,3)
r=0;
return
end
r=1;%均不相同
%%
.
.
function s=destination()
global n node;
if node(n,1)==0 && node(n,2)==0 && node(n,3)==0
s=1;
return
end
s=0;
2. 运用启发式函数
%%
%野人和传教士过河问题
%date:2010/12/15
%author:wang shi ting
function [ ]=guohe()
clear all;
close all;
global n node open_list index;
n=2;
result=zeros(100,1);
node=zeros(100,5);
node(1,:)=[3,3,1,1,-1];%初始化
%1左岸传教士数 2左岸野人数 3船(1为左岸,0为右岸)
%4是否可扩展(1为可扩展) 5父节点号(-1表示无父节点,即为初始节点)
index=1;
open_list=[1,0.01];%节点号 启发函数值
while (1)
[row,~]=size(open_list);
if row==0
fprintf('all the nodes in open list have been expanded.');
return
end
for i1=1:row
open_list(i1,2)=6.01-node(open_list(i1,1),1)-node(open_list(i1,1),2);%定义启发函数
if node(open_list(i1,1),4)==-1%如果该结点是目标结点,则打印结果
fprintf('传教士野人过河问题n');
j=1;
k=open_list(i1,1);
StepNum=1;
.
.
while (k~=-1)
result(j)=k;
k=node(k,5);
j=j+1;
end
j=j-1;
fprintf('方法如下n');
while j>1
BoatPriNum=node(result(j),1)-node(result(j-1),1);
BoatWildNum=node(result(j),2)-node(result(j-1),2);
if node(result(j),3)==1
fprintf('第%d次:左岸到右岸,传教士过去%d人,野人过去%d人n',...
StepNum,abs(BoatPriNum),abs(BoatWildNum));
StepNum=StepNum+1;
end
if node(result(j),3)==0
fprintf('第%d次:右岸到左岸,传教士过去%d人,野人过去%d人n',...
StepNum,abs(BoatPriNum),abs(BoatWildNum));
StepNum=StepNum+1;
end
j=j-1;
end
pause(0.2);
fprintf('问题结束n');
return
end
end
[r_row,~,~]=find(open_list(:,2)==max(open_list(:,2)));
j=open_list(r_row(1,1),1);
if node(j,3)==1 %船在左岸
if ( (node(j,1)==0) || (node(j,1)==3) )&&(node(j,2)>=1)
forward(j,0,1);
end
if (node(j,1)==1 && node(j,2)==1 || node(j,1)==3 && node(j,2)==2)
forward(j,1,0);
end
if (node(j,1)>=1 && node(j,1)==node(j,2))
forward(j,1,1);
end
if (node(j,1)==0 || node(j,1)==3)&& node(j,2)>=2
forward(j,0,2);
.
.
end
if (node(j,1)==2 && node(j,2)==2 || node(j,1)==3 && node(j,2)==1)
forward(j,2,0);
end
elseif node(j,3)==0%船在右岸
if ( (node(j,1)==0) || (node(j,1)==3) )&&(node(j,2)<=2)
afterward(j,0,1);
end
if (node(j,1)==2 && node(j,2)==2 || node(j,1)==0 && node(j,2)==1)
afterward(j,1,0);
end
if (node(j,1)<=2 && node(j,1)==node(j,2))
afterward(j,1,1);
end
if (node(j,1)==0 || node(j,1)==3)&& node(j,2)<=1
afterward(j,0,2);
end
if (node(j,1)==1 && node(j,2)==1 || node(j,1)==0 && node(j,2)==2)
afterward(j,2,0);
end
end
%display(open_list);
open_list(r_row(1),:)=[ ];
index=index-1;%open表个数减1
%display(open_list);
end
%%
%从左岸到右岸,船上传教士x个,野人y个
function []=forward(z,x,y)
global n;
global node open_list index;
node(n,1)=node(z,1)-x;
node(n,2)=node(z,2)-y;
node(n,3)=0;
r=search(z);
if(~r)
return
end
node(z,4)=0;
node(n,4)=1;
node(n,5)=z;
.
.
s=destination();
if s
node(n,4)=-1;
end
index=index+1;
open_list(index,1)=n;
n=n+1;
%%
%%从右岸到左岸,船上传教士x个,野人y个
function []=afterward(z,x,y)
global n;
global node open_list index;
node(n,1)=node(z,1)+x;
node(n,2)=node(z,2)+y;
node(n,3)=1;
r=search(z);
if(~r)
return
end
node(z,4)=0;
node(n,4)=1;
node(n,5)=z;
s=destination();
if s
node(n,4)=-1;
end
index=index+1;
open_list(index,1)=n;
n=n+1;
%%
function r=search(x)
global n node;
i=x;
while node(i,5)~=-1
if node(i,1)==node(n,1) && node(i,2)==node(n,2) && node(i,3)==node(n,3)
r=0;
return
.
.
end
i=node(i,5);
end
%跟初始节点比较
if node(i,1)==node(n,1) && node(i,2)==node(n,2) && node(i,3)==node(n,3)
r=0;
return
end
r=1;%均不相同
%%
function s=destination()
global n node;
if node(n,1)==0 && node(n,2)==0 && node(n,3)==0
s=1;
return
end
s=0;
.
版权声明:本文标题:传教士野人过河问题-两种解法思路 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/p/1703353101a448112.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论