传教士与野人过河问题
传教士野人过河问题-两种解法思路
实验 传教士野人过河问题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 RM 3 0 M 0 3C 3 0 C 0 3B 1 0 B 0 1(2) 确定状态组,分别列出初始状态集和目标状态集用三元组来表示f S :(ML , CL , BL )(均为左岸状态)其中03,03ML CL ≤≤≤≤,BL ∈{ 0 , 1}0S :(3 , 3 , 1) g S : (0 , 0 , 0)初始状态表示全部成员在河的的左岸;目标状态表示全部成员从河的左岸全部渡河完毕。
(3) 定义并确定规则集合仍然以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij 操作。
其中,第一下标i 表示船载的传教士数,第二下标j 表示船载的食人者数;同理,从右岸将船划回左岸称之为Qij 操作,下标的定义同前。
则共有10种操作,操作集为F={P01,P10,P11,P02,P20,Q01,Q10,Q11,Q02,Q20}P 10 if ( ML ,CL , BL=1 ) then ( ML –1 , CL , BL –1 )P 01 if ( ML ,CL , BL=1 ) then ( ML , CL –1 , BL –1 )P 11 if ( ML ,CL , BL=1 ) then ( ML –1 , CL –1 , BL –1 )P 20 if ( ML ,CL , BL=1 ) then ( ML –2 , CL , BL –1 )P 02 if ( ML ,CL , BL=1 ) then ( ML , CL –2 , BL –1 )Q 10 if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 )Q 01 if ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 )Q 11 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 )Q02if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 )(4)当状态数量不是很大时,画出合理的状态空间图图1 状态空间图箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
求解野人与传教士问题1
题目分析:
定义节点的结构:以取般的一个来回作为一步搜索,这样节点可由下面几个量进行描述:两岸的传教士人数和野人人数、本节点距离起始节点的距离,即由初始节点搜索几步后到达本节点。需要注意的是并不是所有节点都是可达的,题目中对可达节点作出了限制,只有两大 岸上的人数必须不能为负。
void goon(); //判断是否继续搜索
void main()
{
int flag; //标记扩展是否成功
for(;;)
{
initiate();
flag=search()
if(flag==1)
releasemem();
goon();
}
}
}
void initiate()
{
int x;
char choice;
uend=unopened=(struc SPQ*)malloc(sizeof(spq));
void releasemem(); //释放占用内存
void showresult(); //显示解
void addtoopened(struc SPQ *ntx); //将节点ntx从UNOPENED链表移至OPRNENED
//链表中
newnode -> sst = sst;
newnode -> spt = spt;
newnode -> ssr = 0
newnode -> spr = 0
传教士与野人过河问题
传教士-野人问题有N个传教士和N个野人要过河,现在有一条船只能承载K个人(包括野人),K<N,在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数。
设M为传教士的人数,C为野人的人数,用状态空间发求解此问题的过程如下:M、C = N,boat = k,要求M>=C且M+C <= K初始状态目标状态L R L RM 3 0 M 0 3C 3 0 C 0 3B 1 0 B 0 1(1)用三元组来表示(ML , CL , BL)其中0<=ML , CL <= 3 , BL ∈{ 0 , 1}(3 , 3 , 1) (0 , 0 , 0)(2)规则集合P10if ( ML ,CL , BL=1 ) then ( ML–1 , CL , BL –1 )P01if ( ML ,CL , BL=1 ) then ( ML , CL–1 , BL –1 )P11if ( ML ,CL , BL=1 ) then ( ML–1 , CL–1 , BL –1 )P20if ( ML ,CL , BL=1 ) then ( ML–2 , CL , BL –1 )P02if ( ML ,CL , BL=1 ) then ( ML , CL–2 , BL –1 )Q10if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 )Q01if ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 )Q11if ( ML ,CL , BL=0 ) then ( ML+1 , CL +1, BL +1 )Q20 if ( ML ,CL , BL=0 ) then ( ML+2 , CL +2, BL +1 )Q02if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 )(3)寻找一个启发式函数引导规则的选用右岸总人数6 – ML – CL 两岸中传教士数目>=野人数目f =–∞其它f=3 Q 01f=2 P 02 f=1 Q 01f=1 Q 11f=1 P 01 f=2 P 11 (3,3,1) (3,2,0)(2,2,0) (3,1,0) (3,2,1) (3,0,0) f=3 P 02(3,1,1) f=2 Q 01(1,1,0) f=4 P 20(2,2,1) f=2 Q 11(1,1,0) f=4 P 20(2,2,1) f=2 Q 11(0,2,0) f=4 P 20(0,3,1)f=3 Q 01(0,1,1)f=5 P 02(0,2,1) f=4 Q 01 (0,0,0)f=3 Q 01(1,1,1) f=4 Q 106.2.3 用状态空间法求解传教士和食人者问题例6-2 传教士和食人者问题(The Missionaries and Cannibals Problem)。
传教士问题
一.问题描述有M个传教士和N个野人来到河边准备渡河,河岸有一条船,每次至多可供k人乘渡。
任何时刻在河的两岸以及船上的野人数目总是不超过传教士的数目。
二.问题分析本问题采用A*算法求解,解答的关键与难点如下:1.评估函数的建立。
评估函数为f=h+d=M+N-2*B+d.。
M表示左岸的传教士的人数,N表示左岸野人的数目,B取值为0或1 。
1表示船在左岸,0 表示船在右岸。
d 表示节点的深度。
下面我们来证明h(n)=M+C-2B是满足A*条件的。
我们分两种情况考虑。
先考虑船在左岸的情况。
如果不考虑限制条件,也就是说,船一次可以将三人从左岸运到右岸,然后再有一个人将船送回来。
这样,船一个来回可以运过河2人,而船仍然在左岸。
而最后剩下的三个人,则可以一次将他们全部从左岸运到右岸。
所以,在不考虑限制条件的情况下,也至少需要摆渡[(M+N-3)/2]*2+1次。
其中分子上的"-3"表示剩下三个留待最后一次运过去。
除以"2"是因为一个来回可以运过去2人,需要[(M+N-3)/2]个来回,而"来回"数不能是小数,需要向上取整,这个用符号[ ]表示。
而乘以"2"是因为一个来回相当于两次摆渡,所以要乘以2。
而最后的"+1",则表示将剩下的3个运过去,需要一次摆渡。
化简有:M+N-2。
再考虑船在右岸的情况。
同样不考虑限制条件。
船在右岸,需要一个人将船运到左岸。
因此对于状态(M,N,0)来说,其所需要的最少摆渡数,相当于船在左岸时状态(M+1,N,1)或(M,N+1,1)所需要的最少摆渡数,再加上第一次将船从右岸送到左岸的一次摆渡数。
因此所需要的最少摆渡数为:(M+N+1)-2+1。
其中(M+N+1)的"+1"表示送船回到左岸的那个人,而最后边的"+1",表示送船到左岸时的一次摆渡。
传教士和野人过河
实验报告一、实验名称:传教士和野人过河二、实验目的:这是经典的过河方案规划问题,通过本实验的设计与编程实现让学生掌握基于状态空间知识表示方法的一般搜索策略。
三、实验内容:设有3个传教士和3个野人同在河的左岸,他们都要到对岸去;河里只有一条船,他们都会划船,但每次渡船至多只能乘两人;如果在任何一岸上,也认的数量超过传教士,野人就要吃掉传教士,要求设计算法,用船将3个传教士和3个野人安全的从左岸移到右岸。
四、实验设计(一)所用的语言:c++语言(二)数据结构节点状态用列表(m,c,b)表示,其中m表示传教士在左岸的人数; c表示野人在左岸的人数;b表示船是否在左岸,当b=1时,表示船在左岸,当b=0时,表式船在右岸。
初始状态:(3,3,1)目标状态: (0,0,0)操作算子:船上人数组合(m,c)共5种(1,0),(1,1),(2,0),(0,1),(0,2)因此算法有10种1)从右岸向左岸过1个传教士,0个野人2)从右岸向左岸过1个传教士,1个野人3)从右岸向左岸过2个传教士,0个野人4)从右岸向左岸过0个传教士,1个野人5)从右岸向左岸过0个传教士,2个野人6)从左岸向右岸过1个传教士,0个野人7)从左岸向右岸过1个传教士,1个野人8)从左岸向右岸过2个传教士,0个野人9)从左岸向右岸过0个传教士,1个野人10)从左岸向右岸过0个传教士,2个野人状态节点: typedef struct st{int m;//传教士int c;//野人int b;//船左}state;//状态将有效的节点存储在树中Tree 中的节点typedef struct hnode{state s;struct hnode *left;struct hnode *right;}node;Open表,closed表用队列存储//定义队列中的节点typedef struct Queuenode{node * np;struct Queuenode* next;}Qnode;//队列中节点//定义队列typedef struct Queue{Qnode *front;Qnode *rear;}queue;(三)算法流程1.用起始节点(3,3,1) 初始化tree,初始化open表,closed表。
传教士和野人问题
传教士和野人问题(Missionaries and Cannibals)传教士和野人问题是一个经典的智力游戏问题。
在这个问题中,实际上隐含了这样一个条件:如果在河的某一岸只有野人,而没有传教士,也同样被认为是合法状态。
在具体书写某些条件时,为了简便,这一点有时并没有考虑,但我们默认这个条件是被考虑了的。
有N个传教士和N个野人来到河边准备渡河,河岸有一条船,每次至多可供k人乘渡。
问传教士为了安全起见,应如何规划摆渡方案,使得任何时刻,在河的两岸以及船上的野人数目总是不超过传教士的数目。
即求解传教士和野人从左岸全部摆渡到右岸的过程中,任何时刻满足M(传教士数)≥C (野人数)和M+C≤k的摆渡方案。
设N=3,k=2,则给定的问题可用图1.2表示,图中L和R表示左岸和右岸,B=1或0分别表示有船或无船。
约束条件是:两岸上M≥C,船上M+C≤2。
图1.2 M-C问题实例由于传教士和野人数是一个常数,所以知道了一岸的情况,另一岸的情况也就知道了。
因此为了简便起见,在描述问题时,只描述一岸--如左岸--的情况就可以了。
另外,该问题我们最关心的是在摆渡过程中,两岸状态的变化情况,因此船上的情况并不需要直接表达出来。
在一次摆渡过程中,船上究竟有几个传教士和野人,可以通过两个相连的状态简单得到。
这样表达更简练,突出了问题的重点。
(1)综合数据库:用三元组表示左岸的情况,即(,,),其中0≤,≤3,∈{0,1},其中表示在左岸的传教士人数,表示在左岸的野人数,=1表示船在左岸,=0表示船在右岸。
则此时问题描述可以简化为:(3,3,1)→(0,0,0)N=3的M-C问题,状态空间的总状态数为4×4×2=32,根据约束条件的要求,可以看出只有20个合法状态。
再进一步分析后,又发现有4个合法状态实际上是不可能达到的。
因此实际的问题空间仅由16个状态构成。
下表列出分析的结果:()(001)达不到(传教士()(000)均在右,船在左)(011)(021)(031)(101)不合法(右岸野人多)(111)(121)不合法(左岸野人多)(131)不合法(左岸野人多)(201)不合法(右岸野人多)(211)不合法(右岸野人多)(221)(231)不合法(左岸野人多)(301)达不到(311)(321)(331)(010)(020)(030)达不到(100)不合法(右岸野人多)(110)(120)不合法(左岸野人多)(130)不合法(左岸野人多)(200)不合法(右岸野人多)(210)不合法(右岸野人多)(230)不合法(右岸野人多)(300)(220)(310)(320)(330)达不到规则集可以划分为两组:一组是从左岸到右岸,称为p 操作,另一组是从右岸到左岸,称为q操作。
修道士与野人问题
6.修道士与野人问题这是一个古典问题。
假设有n个修道士和n个野人准备渡河,但只有一条能容纳c人的小船,为了防止野人侵犯修道士,要求无论在何处,修道士的个数不得少于野人的人数(除非修道士个数为0)。
如果两种人都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出一个小船来回次数最少的最佳方案。
要求:(1)用一个三元组(x1,x2,x3)表示渡河过程中各个状态。
其中,x1表示起始岸上修道士个数,x2表示起始岸上野人个数,x3表示小船位置(0——在目的岸,1——在起始岸)。
例如(2,1,1)表示起始岸上有两个修道士,一个野人,小船在起始岸一边。
采用邻接表做为存储结构,将各种状态之间的迁移图保存下来。
(2)采用广度搜索法,得到首先搜索到的边数最少的一条通路。
(3)输出数据若问题有解(能渡过河去),则输出一个最佳方案。
用三元组表示渡河过程中的状态,并用箭头指出这些状态之间的迁移:目的状态←…中间状态←…初始状态。
若问题无解,则给出“渡河失败”的信息。
(4)求出所有的解。
1.需求分析有n个修道士和n个野人准备渡河,但只有一条能容纳c人的小船,为了防止野人侵犯修道士,要求无论在何处,修道士的个数不得少于野人的人数,否则修道士就会有危险,设计一个算法,确定他们能否渡过河去,若能,则给出一个小船来回次数最少的最佳方案。
用三元组(x1,x2,x3)来表示渡河过程中各个状态,其中,x1表示起始岸上修道士个数,x2表示起始岸上野人个数,x3表示小船位置(0——在目的岸,1——在起始岸)。
若问题有解(能渡过河去),则输出一个最佳方案。
用三元组表示渡河过程中的状态,并用箭头指出这些状态之间的迁移:目的状态←…中间状态←…初始状态,若问题无解,则给出“渡河失败”的信息。
2.设计2.1 设计思想(1)数据结构设计逻辑结构设计: 图型结构存储结构设计: 链式存储结构采用这种数据结构的好处:便于采用广度搜索法,得到首先搜索到的边数最少的一条通路,输出一个最佳方案,采用图的邻接表存储结构搜索效率较高。
传教士和野人渡河
传教士和野人渡河问题作品报告有5个传教士和5个野人过河,只有一条能装下3个人的船,在河的任何一方或者船上,如果野人的人数大于传教士的人数,那么传教士就会有危险。
请设计合适的摆渡方案,并使得所需的摆渡次数最少。
源代码:#include "stdio.h"#include "string.h"#define STEP_MAX 20 //来回过河的最大次数#define NO 5 //野人和传教士各有的人数#define HEAVY 3 //船的最大载重量typedef struct{int wild; //右岸上的野人数int man; //右岸上的传教士数int boat_state; //0表示在左岸,1表示在右岸}state;typedef struct{int wild; //船上的野人数int man; //船上的传教士数int boat_run; //0表示去左岸,1表示去右岸}boat;state now[STEP_MAX]={0}; //保存过河过程中对岸的状态boat path[STEP_MAX]={0}; //保存过河的路径int suit_NO=STEP_MAX; //最合适的过河次数,初始值为一足够的数boat suit_path[STEP_MAX]; //最合适的过河方式//是否全部过河bool All(state c){//右岸的最终状态const state cs={NO,NO,1};if(memcmp(&cs,&c,sizeof(state))==0){return true;}return false;}//传教士是否有危险bool Danger(state ca){if ((ca.wild>ca.man&&ca.man>0)||(NO-ca.wild>NO-ca.man&&NO-ca.man>0)) {return true;}elsereturn false;}//判断该状态是否与前面的一样bool Same(state cs,int n){for (int i=0;i<n;i++){if (memcmp(&cs,&now[i],sizeof(state))==0){return true;}}return false;}//将最短路径保存到suit_path中void Min(int n,boat path[]){if (n<suit_NO){suit_NO=n;memcpy(&suit_path[0],&path[0],n*sizeof(boat));}}//查找过河方案void Cross(int n){int i,j;if (All(now[n])){Min(n,path);return;}if (Danger(now[n])){return;}if (Same(now[n],n)){return;}if(now[n].boat_state==0)//船在左岸时{for(i=0;i<=HEAVY && i<=NO-now[n].wild;i++){for(j=0;j<=HEAVY-i && j<=NO-now[n].man;j++){if (i==0 && j==0){continue;}path[n].wild=i;path[n].man=j;path[n].boat_run=1;memcpy(&now[n+1],&now[n],sizeof(state));now[n+1].wild+=i;now[n+1].man+=j;now[n+1].boat_state=1;Cross(n+1);}}}else//船在右岸时{for(i=0;i<=HEAVY && i<=now[n].wild;i++){for(j=0;j<=HEAVY-i && j<=now[n].man;j++){if (i==0 && j==0){continue;}path[n].wild=i;path[n].man=j;path[n].boat_run=0;memcpy(&now[n+1],&now[n],sizeof(state));now[n+1].wild-=i;now[n+1].man-=j;now[n+1].boat_state=0;Cross(n+1);}}}}void main(){Cross(0);for(int i=0;i<suit_NO;i++){if(path[i].boat_run==0)printf("第%d次过河,从右岸到左岸,船上野人数为%d,传教士数为%d.\n",i+1,suit_path[i].wild,suit_path[i].man);elseprintf("第%d次过河,从左岸到右岸,船上野人数为%d,传教士数为%d.\n",i+1,suit_path[i].wild,suit_path[i].man);}}使用方法:上述程序主要采用了递归调用和近似于枚举的方法。
传教士野蛮人过河问题--python
传教⼠野蛮⼈过河问题--python三名传教⼠和三个野蛮⼈同在⼀个⼩河渡⼝,渡⼝上只有⼀条可容两⼈的⼩船。
问题的⽬标是要⽤这条⼩船把这六个⼈全部渡到对岸去,条件是在渡河的过程中,河两岸随时都保持传教⼠⼈数不少于野蛮⼈的⼈数,否则野蛮⼈会把处于少数的传教⼠状态集合为(x,y,b)三元组,x表⽰左岸野⼈数,y表⽰左岸传教⼠数,x,y取值0~3。
b为0表⽰船在左边,b为1表⽰船在右边动作集合为⼀个传教⼠从左到右,两个传教⼠从左到右,⼀个野⼈从左到右,两个野⼈从左到右,⼀个野⼈⼀个传教⼠从左到右;从右到左类似也有5个动作,共10个动作,于是就可以画出⼀个状态转换图,下⾯的python代码可以帮助我们完成这个任state_legal判断给定状态是否合法,act_legal判断在当前状态执⾏给定动作是否合法,f(x,y,b)打印所有从(x,y,b)可以执⾏的动作和转移到的状态def state_legal(x, y, b):if x < 0 or y < 0 or x > 3 or y > 3:return Falseif y < x and y > 0:return Falseelif (3-y) < 3-x and 3-y > 0:return Falseelse:return Truedef act_legal(x, y, b, xx, yy, bb):if b != bb:return Falseif b == 0 and state_legal(x - xx, y - yy, 1 - b):return Trueelif b == 1 and state_legal(x + xx, y + yy, 1 - b):return Trueelse:return False#when calling f, (x,y,b) is ensured to be state_legaldef f(x,y,b):for act in actions:if act_legal(x, y, b, act[0], act[1], act[2]):if act[2] == 0:print(x,y,b,"---",act, '---', x - act[0], y - act[1], 1 - b)else:print(x,y,b,"---",act, '---', x + act[0], y + act[1], 1 - b)a = (0,1,2,3)actions = []for b in (0,1):for x in (0,1,2):for y in (0,1,2):if x + y >= 1 and x + y <= 2:actions.append((x,y,b))print(actions)for x in a:for y in a:for b in (0,1):if not(x == 0 and y == 0) and state_legal(x, y, b):f(x,y,b)#x is num of savages, y is num of missionaries。
有N个传教士和N个野人来到河边渡河
有N个传教士和N个野人来到河边渡河, 河岸有一条船, 每次至多可供k人乘渡。
问传教士为了安全起见, 应如何规划摆渡方案, 使得任何时刻, 河两岸以及船上的野人数目总是不超过传教士的数目(否则不安全, 传教士有可能被野人吃掉)。
即求解传教士和野人从左岸全部摆渡到右岸的过程中, 任何时刻满足M(传教士数)≥C(野人数)和M+C≤k的摆渡方案。
我们此处举例, 只讨论N为3、k为2的乘渡问题, 这样传教士和野人问题的描述就具体为如下:三个传教士与三个野人来到河边, 有一条船可供一人或两人乘渡, 问题是如何用这条船渡河才能使得河的任一岸上野人的数目总不超过传教士的数目(当然, 如果某一岸上只有野人而没有传教士是允许的)?我们用一个三元组(m c b)来表示河岸上的状态, 其中m、c分别代表某一岸上传教士与野人的数目, b=1表示船在这一岸, b=0则表示船不在。
设N=3, k=2, 则给定的问题可用下图表示, 图中L和R表示左岸和右岸, B=1或0分别表示有船或无船。
约束条件是: 两岸上M≥C, 船上M+C≤2。
我们采用产生式系统来解决这一问题。
由于传教士与野人的总数目是一常数, 所以只要表示出河的某一岸上的情况就可以了, 为方便起见, 我们选择传教士与野人开始所在的岸为所要表示的岸, 并称其为左岸, 另一岸称为右岸。
但显然仅用描述左岸的三元组描述就足以表示出整个情况, 因此必须十分重视选择较好的问题表示法。
以后的讨论还可以看到高效率的问题求解过程与控制策略有关, 合适的控制策略可缩小状态空间的搜索范围, 提高求解的效率。
因而问题的初始状态是(3 3 1), 目标状态是(0 0 0)。
(1) 综合数据库: 用三元组表示, 即(ML, CL, BL), 其中0≤ML, CL≤3, BL∈{0, 1}此时问题述简化为(3, 3, 1)® (0, 0, 0)N=3的M-C问题, 状态空间的总状态数为4×4×2=32, 根据约束条件的要求, 可以看出只有20个合法状态。
传教士野人过河问题两种解法思路
第6次:右岸到左岸,传教士过去1人,野人过去1人
第7次:左岸到右岸,传教士过去2人,野人过去0人
第8次:右岸到左岸,传教士过去0人,野人过去1人
第9次:左岸到右岸,传教士过去0人,野人过去2人
第10次:右岸到左岸,传教士过去1人,野人过去0人
第11次:左岸到右岸,传教士过去1人,野人过去1人
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)
二、解答步骤
(1)设置状态变量并确定值域
M为传教士人数,C为野人人数,B为船数,要求M>=C且M+C<=3,L表示左岸,R表示右岸。
初始状态ﻩﻩ目标状态
LﻩRﻩﻩﻩLR
Mﻩ30ﻩﻩﻩM03
Cﻩ30ﻩﻩﻩﻩﻩC03
B1ﻩ0ﻩﻩﻩﻩB0ﻩ1
(2)确定状态组,分别列出初始状态集和目标状态集
用三元组来表示 :(ML,CL,BL)(均为左岸状态)
图1状态空间图
箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
三、算法设计
方法一:树的遍历
根据规则由根(初始状态)扩展出整颗树,检测每个结点的“可扩展标记”,为“-1”的即目标结点。由目标结点上溯出路径。
见源程序1。
方法二:启发式搜索
构造启发式函数为:
选择较大值的结点先扩展。
野人传教士过河问题
一、对N=5、k≤3时,求解传教士和野人问题的产生式系统各组成部分进行描述(给出综合数据库、规则集合的形式化描述,给出初始状态和目标条件的描述),并画出状态空间图。
答:用M表示传教士,C表示野人,B表示船,L表示左岸,R表示右岸。
初始状态:目标状态:1,综合数据库定义三元组:(M,C,B)其中:0=<M l<=5,表示传教士在河左岸的人数。
0=<C l<=5,表示野人在河左岸的人数。
B l属于集合(0,1),B l=1,表示船在左岸,B l=0,表示船在右岸。
2,规则集规则集可以用两种方式表示,两种方法均可。
按每次渡河的人数分别写出每一个规则,共(3 0)、(0 3)、(2 1)、(1 1)、(1 0)、(0 1)、(2 0)、(0 2)八种渡河的可能(其中(x y)表示x个传教士和y个野人上船渡河),因此共有16个规则(从左岸到右岸、右岸到左岸各八个)。
注意:这里没有(1 2),因为该组合在船上的传教士人数少于野人人数。
规则集如下:IF (M l, C l, 1) THEN (M l -3, C l, 0) p30IF (M l, C l, 1) THEN (M l, C l -3, 0) p03IF (M l, C l, 1) THEN (M l -2, C l -1, 0) p21IF (M l, C l, 1) THEN (M l -1, C l -1, 0) p11IF (M l, C l, 1) THEN (M l -1, C l, 0) p10IF (M l, C l, 1) THEN (M l, C l -1, 0) p01IF (M l, C l, 1) THEN (M l -2, C l, 0) p20IF (M l, C l, 1) THEN (M l, C l -2, 0) p02IF (M l , C l, 0) THEN (M l +3, C l, 1) q30IF (M l, C l, 0) THEN (M l, C l +3, 1) q03IF (M l, C l, 0) THEN (M l +2, C l +1, 1) q21IF (M l, C l, 0) THEN (M l +1, C l +1, 1) q11IF (M l, C l, 0) THEN (M l +1, C l, 1) q10IF (M l, C l, 0) THEN (M l, C l +1, 1) q01IF (M l, C l, 0) THEN (M l +2, C l, 1) q20IF (M l, C l, 0) THEN (M l, C l +2, 1) q02第二种方法:将规则集综合在一起,简化表示。
C++实现传教士与野人过河问题实验报告
else operation.push_back(" 0
2 | 右岸->左岸");
currentState.churchL = lastcurrentState.churchL;
currentState.wildL = lastcurrentState.wildL - 2 * lastcurrentState.boat;
currentState.boat = -lastcurrentState.boat;
lastParameters.push_back(currentState);
CvsWdfs(currentState, lastParameters,operation, 0);
operation.pop_back();
lastParameters.pop_back(); return 0; }
int main(){ int churchL = 3, wildL = 3, churchR = 0, wildR = 0;//分别用来计算左岸和右岸的传教士
和野人 vector <riverSides> lastParameters;//保存每一步移动操作的两岸传教士、野人人数 vector <string> operation;//保存当前操作的描述
if (lastcurrentState.boat == lastParameters[i].boat) return 0;
} } //检验人数数据合法性 if (lastcurrentState.churchL < 0 || lastcurrentState.wildL < 0 || lastcurrentState.churchR < 0 || lastcurrentState.wildR < 0)
实验二 传教士与野人过河问题
实验二 传教士与野人过河问题一、实验目的理解并熟悉掌握深度优先搜索和广度优先搜索算法。
二、实验内容设有3个传教士和3个野人来到河边,打算乘一只船从左岸到右岸去。
该船的负载能力为两人。
在任何时候,如果野人人数超过传教士人数,野人就会把传教士吃掉。
他们怎样才能用这条船安全的把所有人都渡过河去?三、实验内容(1)设置状态变量并确定值域设M 为传教士人数,C 为野人人数,B 为船数,要求M>=C 且M+C <= 3, L 表示左岸,R 表示右岸。
初始状态目标状态 L RL R M 3 0M 0 3 C 3 0C 0 3 B 1 0B 0 1(2)确定状态组,分别列出初始状态集和目标状态集用三元组来表示f S :(ML , CL , BL )(均为左岸状态) 其中,03,03ML CL ≤≤≤≤,BL ∈{ 0 , 1}0S :(3 , 3 , 1) g S : (0 , 0 , 0)初始状态0S :表示全部成员在河的的左岸;目标状态g S :表示全部成员从河的左岸全部渡河到河的右岸。
(3)定义并确定规则集合 以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij 操作。
其 中,第一下标i 表示船载的传教士数,第二下标j 表示船载的食人者数;同理,从右岸将船划回左岸称之为Qij操作,下标的定义同前。
则共有10种操作,操作集为: F={P01,P10,P11,P02,P20,Q01,Q10,Q11,Q02,Q20}if ( ML ,CL , BL=1 ) then ( ML–1 , CL , BL –1 ) P10Pif ( ML ,CL , BL=1 ) then ( ML , CL–1 , BL –1 ) 01if ( ML ,CL , BL=1 ) then ( ML–1 , CL–1 , BL –1 ) P11Pif ( ML ,CL , BL=1 ) then ( ML–2 , CL , BL –1 ) 20if ( ML ,CL , BL=1 ) then ( ML , CL–2 , BL –1 ) P02if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 ) Q10Qif ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 ) 01if ( ML ,CL , BL=0 ) then ( ML+1 , CL +1, BL +1 ) Q11if ( ML ,CL , BL=0 ) then ( ML+2 , CL +2, BL +1 ) Q20if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 ) Q02(4)当状态数量不是很大时,画出合理的状态空间图箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和野人数。
传教士和野人渡河问题
传教士和野人渡河问题刘宪国050422023野人过河问题描述如下:有三个传教士和三个野人过河,只有一条能装下两个人的船,在河的任何一方或者船上,如果野人的人数大于传教士的人数,那么传教士就会有危险.一、算法分析先来看看问题的初始状态和目标状态,假设分为甲岸和乙岸:初始状态:甲岸,3野人,3传教士;乙岸,0野人,0传教士;船停在甲岸,船上有0个人;目标状态:甲岸,0野人,0传教士;乙岸,3野人,3传教士;船停在乙岸,船上有0个人;整个问题就抽象成了怎样从初始状态经中间的一系列状态达到目标状态。
问题状态的改变是通过划船渡河来引发的,所以合理的渡河操作就成了通常所说的算符,根据题目要求,可以得出以下5个算符(按照渡船方向的不同,也可以理解为10个算符):渡1野人、渡1传教士、渡1野人1传教士、渡2野人、渡2传教士。
算符知道以后,剩下的核心问题就是搜索方法了,本文采用深度优先搜索,通过一个FindNext(…)函数找出下一步可以进行的渡河操作中的最优操作,如果没有找到则返回其父节点,看看是否有其它兄弟节点可以扩展,然后用Process(…)函数递规调用FindNext(…),一级一级的向后扩展。
搜索中采用的一些规则如下:1、渡船优先规则:甲岸一次运走的人越多越好(即甲岸运多人优先),同时野人优先运走;乙岸一次运走的人越少越好(即乙岸运少人优先),同时传教士优先运走;2、不能重复上次渡船操作(通过链表中前一操作比较),避免进入死循环;3、任何时候河两边的野人和传教士数均分别大于等于0且小于等于3;4、由于只是找出最优解,所以当找到某一算符(当前最优先的)满足操作条件后,不再搜索其兄弟节点,而是直接载入链表。
5、若扩展某节点a的时候,没有找到合适的子节点,则从链表中返回节点a的父节点b,从上次已经选择了的算符之后的算符中找最优先的算符继续扩展b。
二、基本数据结构定义如下几个数据结构:typedef struct _riverside{ // 岸边状态类型int wildMan; // 野人数int churchMan; // 传教士数}RIVERSIDE;typedef struct _boat{ // 船的状态类型int wildMan; // 野人数int churchMan; // 传教士数}BOAT;typedef struct _question{ // 整个问题状态RIVERSIDE riverSide1; // 甲岸RIVERSIDE riverSide2; // 乙岸int side; // 船的位置, 甲岸为-1, 乙岸为1 BOAT boat; // 船的状态_question* pPrev; // 指向前一渡船操作_question* pNext; // 指向后一渡船操作}QUESTION;用QUESTION来声明一个最基本的链表。
野蛮人过河问题算法说明及程序
传教士与野人问题算法及程序说明0810504班一.问题说明有3个传教士和3个野蛮人来到河边,打算乘一只船从左岸渡到右岸。
该船的负载能力为2人,在任何时刻如果野蛮人人数超过传教士人数,野蛮人就会把传教士吃掉。
他们怎样才能用这条船安全让所有人都渡过河。
二.算法说明采用递归算法。
因为每次过河都要遵循几个约定,一为两边岸上野蛮人的数量必须大于传教士的数量,二为船上最多只能装两个人,所以采用递归算法不断嵌套循环模拟每次过河的过程,同时加上若干递归中止返回条件,则可以推得过河的方法。
三.数据结构船结构:即表示船上野蛮人和传教士的个数typedef struct Boat{int numX; /// 传教士个数int numY; /// 野蛮人个数}Boat;从左岸到右岸时船上装的人的种类,有3种,即2个野人和0个传教士,0个野人和2个传教士,1个野人和1个传教士。
Boat LtoR[3]={{2,0},{0,2},{1,1}};从右岸回左岸时船上装的人的种类,有2种,即1个野人或1个传教士Boat RtoL[2]={{1,0},{0,1}};递归函数1: int fnPassRiver1(x1,y1,x2,y2)表示每次由一个野蛮人驾船从右岸回左岸后,再向右过河的过程递归函数2: int fnPassRiver2(x1,y1,x2,y2)表示每次由一个传教士驾船从右岸回左岸后,再向右过河的过程四.具体算法第一次过河时,有三种情况,即2个野人和0个传教士,0个野人和2个传教士,1个野人和1个传教士,所以在主函数中用参数是k的三重for循环,确定整体过河框架。
在接下来的从左向右的过河之前,存在两种可能,即驾船从右边回来的是野蛮人或传教士,因此用两个递归函数fnPassRiver1()和fnPassRiver2()分类。
函数fnPassRiver1()和fnPassRiver2()的内容相似,即先递归中判断止条件,若满足三个条件中的任意一个,都跳出此次循环,回到上一级递归;若不满足,则进入下一级循环,此时改变了函数fnPassRiver1(x1,y1,x2,y2)和fnPassRiver2(x1,y1,x2,y2)中的传递参数x1,y1,x2,y2,改变的依据是数组LtoR[3]中的三组值。
传教士野人过河问题-两种解法思路
实验 传教士野人过河问题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 RM 3 0 M 0 3C 3 0 C 0 3B 1 0 B 0 1(2) 确定状态组,分别列出初始状态集和目标状态集用三元组来表示f S :(ML , CL , BL )(均为左岸状态)其中03,03ML CL ≤≤≤≤,BL ∈{ 0 , 1}0S :(3 , 3 , 1) g S : (0 , 0 , 0)初始状态表示全部成员在河的的左岸;目标状态表示全部成员从河的左岸全部渡河完毕。
(3) 定义并确定规则集合仍然以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij 操作。
其中,第一下标i 表示船载的传教士数,第二下标j 表示船载的食人者数;同理,从右岸将船划回左岸称之为Qij 操作,下标的定义同前。
则共有10种操作,操作集为F={P01,P10,P11,P02,P20,Q01,Q10,Q11,Q02,Q20}P 10 if ( ML ,CL , BL=1 ) then ( ML –1 , CL , BL –1 )P 01 if ( ML ,CL , BL=1 ) then ( ML , CL –1 , BL –1 )P 11 if ( ML ,CL , BL=1 ) then ( ML –1 , CL –1 , BL –1 )P 20 if ( ML ,CL , BL=1 ) then ( ML –2 , CL , BL –1 )P 02 if ( ML ,CL , BL=1 ) then ( ML , CL –2 , BL –1 )Q 10 if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 )Q 01 if ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 )Q 11 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 )Q02if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 )(4)当状态数量不是很大时,画出合理的状态空间图图1 状态空间图箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
传教士野人问题参考答案
传教士-野人问题有N个传教士和N个野人要过河,现在有一条船只能承载K个人(包括野人),K<N,在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数。
设M为传教士的人数,C为野人的人数,用状态空间发求解此问题的过程如下:M、C = N,boat = k,要求M>=C且M+C <= K初始状态目标状态L R L RM 3 0 M 0 3C 3 0 C 0 3B 1 0 B 0 1(1)用三元组来表示(ML , CL , BL)其中0<=ML , CL <= 3 , BL ∈{ 0 , 1}(3 , 3 , 1) (0 , 0 , 0)(2)规则集合P10if ( ML ,CL , BL=1 ) then ( ML–1 , CL , BL –1 )P01if ( ML ,CL , BL=1 ) then ( ML , CL–1 , BL –1 )P11if ( ML ,CL , BL=1 ) then ( ML–1 , CL–1 , BL –1 )P20if ( ML ,CL , BL=1 ) then ( ML–2 , CL , BL –1 )P02if ( ML ,CL , BL=1 ) then ( ML , CL–2 , BL –1 )Q10if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 )Q01if ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 )Q11if ( ML ,CL , BL=0 ) then ( ML+1 , CL +1, BL +1 )Q20 if ( ML ,CL , BL=0 ) then ( ML+2 , CL +2, BL +1 )Q02if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 )(3)寻找一个启发式函数引导规则的选用右岸总人数6 – ML – CL 两岸中传教士数目>=野人数目f =–∞其它f=3 Q 01f=2 P 02 f=1 Q 01f=1 Q 11f=1 P 01 f=2 P 11 (3,3,1) (3,2,0)(2,2,0) (3,1,0) (3,2,1) (3,0,0) f=3 P 02(3,1,1) f=2 Q 01(1,1,0) f=4 P 20(2,2,1) f=2 Q 11(1,1,0) f=4 P 20(2,2,1) f=2 Q 11(0,2,0) f=4 P 20(0,3,1)f=3 Q 01(0,1,1)f=5 P 02(0,2,1) f=4 Q 01 (0,0,0)f=3 Q 01(1,1,1) f=4 Q 106.2.3 用状态空间法求解传教士和食人者问题例6-2 传教士和食人者问题(The Missionaries and Cannibals Problem)。
传教士过河问题(实验二)
传教士过河问题实验报告计研-12 2012312120115 宋玲玲1.实验目的(1)了解知识表示相关技术;(2)掌握问题规约法或者状态空间法的分析方法。
2.实验内容从前有一条河,河的左岸有m个传教士、m个野人和一艘最多可乘n人的小船。
约定左岸,右岸和船上或者没有传教士,或者野人数量少于传教士,否则野人会把传教士吃掉。
搜索一条可使所有的野人和传教士安全渡到右岸的方案。
3.实验原理及方法假设开始时传教士、野人和船都在右岸,用数组(a,b,c)分别表示右岸传教士个数、右岸野人个数、船的位置,则可分为三种情况讨论:A、n>m/2。
此种情况下,先把所有的野人度过去,每次返回一个野人,当出现(m,0,0)情况时,返回m-n个野人(若m==n,返回1个野人)。
然后渡n个传教士,此时野人==传教士,然后返回一个野人和传教士,再开始最大限度的渡传教士,每次返回一个野人,最终直到a==b==c==0;B、n<=3&&n<=m/2 || n==1,显然此时无解;C、n>=4&&n<=m/2,此时只能每次传n/2个传教士和野人,每次返回一个野人和传教士,直到最终结果。
程序流程图如下:4、源程序清单:本程序用C++语言编写。
#include"iostream"using namespace std;bool flag = false; //标记是否有解bool af = false; //标记a是否为0bool bf = false; //当b变为0后赋值为true;bool ef = false; //当a==b后赋值为truebool f = false; //判断n是否大于m/2int m;//传教士野人的个数int n;//船一次能装载的人数void mc(int a,int b,int c);int main(){cout<<"传教士与野人过河问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
贵州航天职业技术学院《C语言程序设计》系别: __计算机科学系 _________班级: __10级软件技术_________姓名: _______________________指导教师: ___陆树芬_______________小组成员: ___翟奇张源李雪_______前言C语言作为一门最通用的语言,在过去很流行,将来依然会如此。
几乎每一个理工科或者其他专业的学生毫不例外地要学习它。
从C 语言产生到现在,它已经成为最重要和最流行的编程语言之一。
在各种流行编程语言中,都能看到C语言的影子,如Java的语法与C 语言基本相同。
学习、掌握C语言是每一个计算机技术人员的基本功之一。
C语言具有高级语言的强大功能,却又有很多直接操作计算机硬件的功能(这些都是汇编语言的功能),因此,C语言通常又被称为中级语言。
学习和掌握C语言,既可以增进对于计算机底层工作机制的了解,又为进一步学习其他高级语言打下了坚实的基础。
本大作业是对学生在课堂上所学知识的一次综合检测。
通过本次大作业的制作,应能综合使用在《C语言程序设计》课程中学到的多种基础知识,并可以很好的应用到实际操作中去,具备简单的项目设计能力。
本大作业主要以传教士和野人怎样从河的一岸完全渡到另一岸,而不发生野人吃掉传教士这一问题展开,主要使用C语言中的链表应用完成程序的设计,将此次程序设计报告分为以下几点:1. 问题的描述:描述本程序的设计内容;2. 问题分析:介绍此程序设计的结构和算法分析3. 程序设计流程图4. 程序各个功能模块的实现5. 程序运行结果:将各种情况下的运行结果通过屏幕截取下来6. 程序设计结论:描述本次程序设计的一些体会和在程序设计过程中所获得的一些知识以及本次程序设计所存在的不足和缺陷。
7. 完成本次程序设计所翻阅的资料目录一.问题描述 ------------------------------------------------------------ 5二.问题分析 ------------------------------------------------------------ 5三.主要流程图 --------------------------------------------------------- 8四. 基本数据类型声明及数据结构-------------------------------- 8五. 程序主要实现说明及设置------------------------------------ 10六.运行结果------------------------------------------------------- 20七. 实验结论 ------------------------------------------------------- 26八.参考文献 ---------------------------------------------------------- 28一.问题描述有M个传教士和N个野人来到河边准备渡河,河岸有一条船,每次至多可供k人乘渡。
任何时刻在河的两岸以及船上的野人数目总是不超过传教士的数目。
二.问题分析1.定义节点的结构:以取船的一个来回作为一步搜索,这样节点可由下面几个量进行描述:两岸的传教士人数和野人人数、船上的传教士人数和野人人数,由初始节点搜索几步后到达本节点。
需要注意的是并不是所有节点都是可达的,题目中对可达节点作出了限制,只有两岸上的人数必须不能为负,且每一时刻野人的人数都必须小于或等于传教士的人数。
2.定义连接:两个节点间的连接可由般从右到左岸时船上的传教士人数、野人人数、船返回时船上的传教士人数、野人人数进行描述。
3.算法分析:先来看看问题的初始状态和目标状态,假设传教士和野人人数都为3人,船的负载人数为2人,河岸分为右岸和左岸:初始状态:右岸 3传教士,3野人;左岸 0传教士,0野人;船停在右岸,船上有0个人;目标状态:右岸 0传教士,0野人;左岸 3传教士,3野人;船停在左岸,船上有0个人;整个问题就抽象成了怎样从初始状态经中间的一系列状态达到目标状态。
问题状态的改变是通过划船渡河来引发的,所以合理的渡河操作就成了通常所说的算符,根据题目要求,可以得出以下5个算符(按照渡船方向的不同,也可以理解为10或更多个算符):渡1野人、渡1传教士、渡1野人1传教士、渡2野人、渡2传教士算符知道以后,剩下的核心问题就是搜索方法:首先定义freeit()函数释放不符合条件的节点,determ()函数判断符合条件的情况,sign()函数判断船的航行方向,copyit()函数复制节点内容,print ()函数显示保存结果,然后在trans()函数中通过调用sign()、copit()、determ()、print()完成渡河既搜索方法。
搜索中采用的一些规则如下:1、渡船优先规则:右岸一次运走的人越多越好(即右岸运多人优先),同时野人优先运走;左岸一次运走的人越少越好(即左岸运少人优先),同时传教士优先运走;2、不能重复上次渡船操作(通过链表中前一操作比较),避免进入死循环;3、任何时候河两边的野人和传教士人数均分别大于或等于0且小于或等于4;4、由于只是找出最优解,所以当找到某一算符(当前最优先的)满足操作条件后,不再搜索其下一节点,而是直接载入链表。
5、若搜索某节点a的时候,没有找到合适的子节点,则从链表中返回节点a的父节点b,从上次已经选择了的算符之后的算符中找最优先的算符继续搜索b三.主要流程图四. 基本数据类型声明及数据结构#include <stdio.h>#include <string.h>#include <conio.h>#include <stdlib.h>FILE *fp;struct a *jj,head; //jj指向各种情况下船上的传教士和野人人数long r,total=0,js=0; /*js渡船的方法数,r 为船的负载人数,total为初始状态到目标状态之间的状态个数*/long k1,k2; //起初传教士和野人的个数/*结构类型a:记录各种情况下船上的传教士和野人数*/struct a{long m,s; //船上的传教士和野人个数struct a *next; //指向下一个接点(a)的指针next};/*建立双向的指针链表,记入符合的情况*/struct aim{long m1,s1; //右岸的传教士和野人个数long m2,s2; //左岸的传教士和野人个数long n; //n为摆渡次数struct aim *back,*next;//指向前一个接点(aim)的指针bake和下一个接点(aim)的指针next};五. 程序主要实现说明及设置1./*释放该接点,并将其上的接点的next指针还原*/void freeit(struct aim *p){struct aim *p1=p;p1=p->back;free(p);if(p1!=NULL)p1->next=NULL;return;}2./*判断函数判断符合条件的情况*/long determ(struct aim *p){struct aim *p1=p;if(p->s1>k2||p->m1>k1||p->s2>k2||p->m2>k1||p-> s1<0||p->s2<0||p->m1<0||p->m2<0)return -1;if(k1>4||k2>4)return -1;if(p->m1!=0)if(p->s1>p->m1)return -1;if(p->m2!=0)if(p->s2>p->m2)return -1;while(p1!=NULL){p1=p1->back;if(p1!=NULL)if(p1->n%2==p->n%2)if(p1->s1==p->s1)if(p1->s2==p->s2)if(p1->m1==p->m1)if(p1->m2==p->m2)return -1;}if(p->s1==0&&p->m1==0) //条件成立摆渡完成返回1if(p->n%2==0)return 1;elsereturn -1;return 0;}3./*符号函数判断是从右到左航行还是从左到右航行*/long sign(long n){if(n%2==0)return -1; //从右到左再返回return 1; //从右到左不反回}4./*复制内容函数*/void copyit(struct aim *p3,struct aim *p) {p3->s1=p->s1;p3->s2=p->s2;p3->m1=p->m1;p3->m2=p->m2;p3->n=p->n+1; //指向下一次摆渡p3->back=p;p3->next=NULL;p->next=p3;}5./*打印函数在屏幕上显示结果并将其存入文件中*/void print(struct aim *p3){struct aim *p=p3;js++;while(p->back){p=p->back;//指向下一个方法的接点}/*********************************/printf("\n方法%ld:\n",js);fprintf(fp,"\n方法%ld:\n",js);/*********************************/while(p){/*********************************/printf("%ld,%ld::%ld,%ld\t",p->m1,p->s1,p->m2,p->s2);fprintf(fp,"%ld,%ld::%ld,%ld\t",p->m1,p->s1,p->m2,p->s2);/*********************************/p=p->next; //指向下一个节点}printf("\n");}6./*转移函数将人从右岸渡到左岸*/void trans(struct aim *p){struct aim *p3;struct a *fla;long i,j,f,e;fla=&head;p3=(struct aim *)malloc(sizeof(struct aim)); f=sign(p->n);for(i=0;i<total;i++){fla=fla->next;copyit(p3,p);/*渡河:右岸人数减去船上所渡人数,左岸人数则加上从右岸渡来的人数*/p3->s1-=fla->s*f;p3->m1-=fla->m*f;p3->s2+=fla->s*f;p3->m2+=fla->m*f;j=determ(p3); //调用判断函数判断符合条件的情况if(j==-1){if(i<total-1){continue;}else{freeit(p3); //调用freeit()释放该接点break;}}if(j==1){if(i<total-1){print(p3);continue;}else{print(p3); //调用print()打印结果freeit(p3);break;}}if(j==0)trans(p3);//递归调用转移函数将人从右岸渡到左岸}if(j==-1)/*********************************/printf("你输入的数据出现错误!\n");printf("请重新运行程序!\n");/*********************************/return;}7./*程序入口*/void main(){struct aim *p,*p1;long j,a ;long e,f;struct a *flag;FILE*fpt;if((fpt=fopen("c:result.txt","w+"))==0){printf("can't creat it\n");exit(0);}fp=fpt;p=(struct aim *)malloc(sizeof(struct aim)); p->back=NULL;p->next=NULL;p->s2=0;p->m2=0;p->n=1;/*********************************/printf("请输入船的负载人数\n");fprintf(fp,"\n请输入船的负载人数\n"); scanf("%ld",&r);fprintf(fp,"\n%ld\n",r);/*********************************//*if(r>3){printf("船太小已经超载了!\n");}*/flag=&head;for(e=0;e<=r;e++)for(f=0;f<=r;f++)if(e+f>0&&e+f<=r){total++;jj=(struct a*)malloc(sizeof(struct a)); jj->m=e;jj->s=f;flag->next=jj;jj->next=NULL;flag=jj;}/*********************************/printf("注意:输入的传教士的人数大于或等于野人个数:\n");printf("请输入传教士和野人的个数: 传教士,野人;\n");fprintf(fp,"\n请输入传教士和野人的个数: 传教士,野人\n");scanf("%ld,%ld",&p->m1,&p->s1);fprintf(fp,"\n%ld,%ld\n",p->m1,p->s1); /**********************************/k1=p->m1;k2=p->s1;if(k1>4||k2>4||k2>k1){printf("你输入的数据出现错误!\n");printf("请重新运行程序!\n");fprintf(fp,"\n你输入的数据出现错误!\n");fprintf(fp,"\n请重新运行程序!\n");}trans(p);fclose(fpt);getch();}六.运行结果1.2.3. 4.5. 6.7. 8.9.10.11.12.七. 实验结论_______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ ______________________________________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________ _______________________八.参考文献(1).李凤霞《C语言程序设计教程》北京理工大学出版社(2).刘枧张宜坤《C语言程序设计》人民邮电出版社(3).贾若刘枧《C语言程序设计上机指导教程》人民邮电出版社附录C语言是一门计算机基础语言,通过这一学期的学习,对于它的一些特点和算法有了一定程度的了解,并能够做一些中等的题目,但并没有完全掌握。