野人与传教士问题A算法

合集下载

修道士与野人问题

修道士与野人问题

.修道士与野人问题这是一个古典问题。

假设有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)数据结构设计逻辑结构设计: 图型结构存储结构设计: 链式存储结构采用这种数据结构的好处:便于采用广度搜索法,得到首先搜索到的边数最少的一条通路,输出一个最佳方案,采用图的邻接表存储结构搜索效率较高。

传教士野人过河问题-两种解法思路

传教士野人过河问题-两种解法思路

实验 传教士野人过河问题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操作的下标,即分别表示船载的传教士数和食人者数。

人工智能:野人与修道士问题

人工智能:野人与修道士问题

野人与修道士问题(Missionaries-and-Cannibals Problem )[修道士与野人问题]:三个野人与三个传教士来到河边,打算乘一只船从右岸渡到左岸去,该船的最大负载能力为两个人。

在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。

用状态空间法表示修道士与野人问题并设计编写计算机程序求问题的解。

问题分析:从上图可知,修道士、野人和船一共有六种可能,M L 、C L 、B L 、M R 、C R 、B R 。

可以表示为q =(M ,C ,B ),其中m 表示修道士的数目(0、1、2、3)、c 表示野人的数目(0、1、2、3)、b 表示船在左岸(1)或右岸(0)。

1、定义状态的描述形式:(m ,c ,b )2、表示所有可能的状态,并确定初始状态集和目标状态集: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)初始状态:(3,3,1)目标状态:(0,0,0)3、定义算符:L ij :把i 个修道士,j 个野人从河的左岸送到右岸R ij :把i 个修道士,j 个野人从河的右岸送到左岸整个问题就抽象成了怎样从初始状态经中间的一系列状态达到目标状态。

问修道士M野 人C 左L 右R题状态的改变是通过划船渡河来引发的,所以合理的渡河操作就成了通常所说的算符,根据题目要求,可以得出以下5个算符(按照渡船方向的不同,也可以理解为10个算符):渡1野人、渡1牧师、渡1野人1牧师、渡2野人、渡2牧师即:L01或R01,L10或R10,L11或R11,L02或R02,L20或R204、状态空间图:5、设计编写计算机程序求问题的解:算法:在应用状态空间表示和搜索方法时,用(M,C,B)来表示状态描述,其中M和C分别表示在左岸的传教士与野人数。

修道士和野人问题

修道士和野人问题

修道⼠和野⼈问题 休闲时刻看看神经⽹络⽅⾯的书,发现了修道⼠和野⼈的问题,不禁勾引起我写算法的欲望,曾经的三只⼤⽼虎三只⼩⽼虎过河问题、⼈狼⽺⽩菜过河问题、汉诺塔、哈夫曼等等各种算法瞬间在脑海中约隐约现,修道⼠和野⼈问题我以前好像没有解开,中午吃饭的时候在脑海中重新构造思路,下午耗了点时间把它⼲掉。

(算法不在代码⾥,⽽在思想中;所以尽量不要看我的代码,⽽要仔细分析我写的思路) 题⽬: 设有3个修道⼠和3个野⼈来到河边,打算⽤⼀条船从河的左岸渡到河的右岸。

但该船每次只能装载两个⼈,在任何岸边野⼈的数⽬都不得超过修道⼠的⼈数,否则修道⼠就会被野⼈吃掉。

假设野⼈服从任何⼀种过河安排,请问如何规划过河计划才能把所有⼈都安全地渡过河去。

⾸先考虑总共有(3+1)*(3+1)= 16 种不同的状态(因为左岸可以有0,1,2,3个传教⼠,左岸可以有0,1,2,3个野⼈),所以可以考虑使⽤穷举法。

使⽤如下C#程序语⾔:int MaxNum = 3;for (int monk = MaxNum; monk >= 0; monk--){for (int savage = MaxNum; savage >= 0; savage--){Console.Write("{{" + monk + "," + savage + "},{" + (MaxNum - monk) + "," + (MaxNum - savage) + "}} ");}Console.Write("\n");}⽣成16种状态图↓↓↓↓↓↓↓↓↓↓↓状态图含义:{a,b}:a,左岸修道⼠数量;b,左岸野⼈数量。

--------仅考虑左岸传教⼠和野蛮⼈数量(所有状态图)------------------------{3,3} {3,2} {3,1} {3,0}{2,3} {2,2} {2,1} {2,0}{1,3} {1,2} {1,1} {1,0}{0,3} {0,2} {0,1} {0,0}其中{3,3}是起始状态图;{0,0}是终⽌状态图。

修道士与野人问题教学文案

修道士与野人问题教学文案

修道士与野人问题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)数据结构设计逻辑结构设计: 图型结构存储结构设计: 链式存储结构采用这种数据结构的好处:便于采用广度搜索法,得到首先搜索到的边数最少的一条通路,输出一个最佳方案,采用图的邻接表存储结构搜索效率较高。

传教士和野人问题

传教士和野人问题

传教士和野人问题传教士和野人问题(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个状态构成。

下表列出分析的结果:( ) ( ) ( 0 0 1)达不到( 0 0 0) (传教士均在右,船在( 0 1 0) 左) ( 0 2 0) ( 0 1 1) ( 0 3 0)达不到 ( 0 2 1) ( 1 0 0)不合法( 0 3 1) (右岸野人多) ( 1 0 1)不合法( 1 1 0) (右岸野人多) ( 1 2 0)不合法( 1 1 1) (左岸野人多) ( 1 2 1)不合法( 1 3 0)不合法(左岸野人多) (左岸野人多) ( 1 3 1)不合法( 2 0 0)不合法(左岸野人多) (右岸野人多) ( 2 0 1)不合法( 2 1 0)不合法(右岸野人多) (右岸野人多) ( 2 1 1)不合法( 2 3 0)不合法(右岸野人多) (右岸野人多) ( 2 2 1) ( 3 0 0) ( 2 3 1)不合法( 2 2 0) (左岸野人多) ( 3 1 0) ( 3 0 1)达不到 ( 3 2 0)( 3 1 1) ( 3 3 0)达不到 ( 3 2 1)( 3 3 1)规则集可以划分为两组:一组是从左岸到右岸,称为p操作,另一组是从右岸到左岸,称为q操作。

传教士和野人问题

传教士和野人问题

传教士和野人问题(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操作。

A星传教士和野人问题

A星传教士和野人问题

A*传教士和野人问题(2008-06-27 10:53:16)转载▼问题描述设有3个传教士和3个野人来到河边,打算乘一只船从左岸渡到右岸去。

该船的负载能力为两人。

在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。

他们怎样才能用这条船安全地把所有人都渡河过去?问题表示:需要考虑两岸的修道士人数和野人人数,船的位置。

用三元式表示状态:S= (m, n, B)其中,m表示左岸修道士人数,n表示左岸野人人数,B表示左岸船的数目。

评估函数的建立。

评估函数为f=d+h=d+M+N-2*BM表示左岸的传教士的人数,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)所需要的最少摆渡数,再加上第一次将船从右岸送到左岸的一次摆渡数。

野人和传教士过河问题的实现1

野人和传教士过河问题的实现1
1
武汉理工大学《计算机软件高级项目实践》课程设计说明书
野人和传教士过河问题的实现
1 课程设计内容与要求
1.1 设计目的
设计有效的数据结构和算法实现野人和传教士过河问题。
1.2 设计内容
1. 深入理解野人和传教士过河问题的实质,调研该问题实现的相关算法; 2. 设计有效的数据结构和算法实现该问题; 3. 根据算法完成程序的编写和调试,要求输出实现的结果; 4. 按课程设计要求撰写报告。
7.2.1 求最快能过河的渡河方案 ................................................................................................. 15 7.2.2 求一种能过河的渡河方案 ................................................................................................. 16 8 总结 .................................................................................................................................................... 18 参考文献 .................................................................................................................................................... 19 附录 1 求一种能过河的渡河方案 ......................................................................................................... 19

传教士野人过河问题两种解法思路

传教士野人过河问题两种解法思路
第5次:左岸到右岸,传教士过去2人,野人过去0人
第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。
方法二:启发式搜索
构造启发式函数为:
选择较大值的结点先扩展。

C++实现传教士与野人过河问题实验报告

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)

野蛮人过河问题算法说明及程序

野蛮人过河问题算法说明及程序

传教士与野人问题算法及程序说明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操作的下标,即分别表示船载的传教士数和食人者数。

野人与传教士问题A算法

野人与传教士问题A算法

野人与传教士问题(A*算法)SY0903620 赵磊一、实验题目请用A*算法实现传教士和野人问题问题:设有3个传教士和3个野人来到河边,打算乘一只船从右岸渡到左岸去。

该船的负载能力为两人。

在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。

他们怎样才能用这条船安全地把所有人都渡过河去?算法设计要求给出:状态表示,规则库,启发函数等二、实验目的通过具体问题的编程求解,利用A*算法解决此经典问题,了解人工智能的启发式搜索算法的基本过程与原理。

三、设计思想1、编程工具采用C++语言在Visual Studio 6.0环境下编写;2、整体思想(1)把初始结点So放入OPEN 表中,计算f(So)。

(2)如果OPEN为空,则搜索失败,退出。

(3)把OPEN中的第一个节点(记为节点n)从表中移出放入CLOSED表。

(4)考察节点n是否为目标节点。

若是,则求得问题的解,退出。

(5)若节点n不可扩展,则转第(2)步。

(6)扩展节点n,用估价函数f(x)计算每个子节点的估价值,并为每个子节点配置指向父节点的指针,把这些子节点都送到OPEN表中,然后对OPEN表中的全部节点按估价值从小到大的顺序排列。

3、具体说明用A*算法求解传教士与野人问题。

M=C=5, K=3。

节点估价值设为f(n)=h(n)+g(n),g(n)设为节点搜索深度,而h(n)= m(n) + c(n) - 2b(n),其中m:河左岸的传教士人数;c:河左岸的野人人数;b:船是否在左岸,1:表示在左岸,0:表示不在左岸。

采用结构体定义形式,定义状态节点*NewNode(int m, int c, int b),其中包含m左岸传教士人数、c左岸野人人数、b船状态(左或右)。

开始状态为(3,3,1),目标状态为(0,0,0)。

若需要条件满足,即任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉,要对状态结点的安全性进行判断,判断一个状态是否为安全的,即是否满足在河的任何一岸,传教士人数不少于野人人数,或者只有野人而没有传教士。

算法及算法的表示

算法及算法的表示

解决该问题的算法违背了算法特征中的( B )
A.唯一性
B.有穷性
C.有0个或多个输入
D.有输出
5.下列关于算法特征的描述中,正确的是( D )
A.算法的有穷性就是指在合理时间内能够完成全部操作 B.任何一个算法都必须要有数据输入 C.确定性是指每一个步骤都要足够简单,是实际能做的 D.算法不可以没有输出
例如: “明日逢春好不晦气,终年倒运少有余财”
——祝枝山
意思一: 明日逢春好,不晦气 终年倒运少,有余财
意思二: 明日逢春,好不晦气 终年倒运,少有余财
2)、流程图描述算法
流程图也称程序框图,是算法的一种图形 化表示方法。
优点:流程图描述算法形象、直观、容易 理解
流程图图例
例1:早上起床以后的过程,可以用以下流程图表示
3.输入:有零个或多个输入; 4.输出:有一个或多个输出,没有输出的算法毫无意义;
5.可行性:算法的每一步都是计算机能够有效执行、
可以实现的。
三、算法的表示:
算法的表示方法有:自然语言、流程图 和计算机语言。
常用的计算机语言有:VB、C、C++ 和java等。
1)、自然语言描述算法
用自然语言描述算法,就是把算法的各个步骤, 依次用人们日常生活中使用的语言描述出来。
②c←c+1
②c←c+1
C.① sum ← sum + d D.① sum ← sum + c
②d←d+1
②d←d+1
9.有下图所示的流程图片断:
其中循环部分执行完后变量t的值是(
A.12
B.18
C.48
【答案】 B
) D.192
10.如下图所示,该流程图所表示的算法违背了算法的有穷性 特征,下列修改方法中,可以改正该错误的是( )

传教士和野人渡河问题

传教士和野人渡河问题

传教士和野人渡河问题刘宪国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来声明一个最基本的链表。

传教士野人过河问题两种解法思路

传教士野人过河问题两种解法思路

实验 传教士野人过河问题王世婷一、实验问题传教士和食人者问题(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. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

野人与传教士问题(A*算法)SY0903620 赵磊一、实验题目请用A*算法实现传教士和野人问题问题:设有3个传教士和3个野人来到河边,打算乘一只船从右岸渡到左岸去。

该船的负载能力为两人。

在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。

他们怎样才能用这条船安全地把所有人都渡过河去?算法设计要求给出:状态表示,规则库,启发函数等二、实验目的通过具体问题的编程求解,利用A*算法解决此经典问题,了解人工智能的启发式搜索算法的基本过程与原理。

三、设计思想1、编程工具采用C++语言在Visual Studio 6.0环境下编写;2、整体思想(1)把初始结点So放入OPEN 表中,计算f(So)。

(2)如果OPEN为空,则搜索失败,退出。

(3)把OPEN中的第一个节点(记为节点n)从表中移出放入CLOSED表。

(4)考察节点n是否为目标节点。

若是,则求得问题的解,退出。

(5)若节点n不可扩展,则转第(2)步。

(6)扩展节点n,用估价函数f(x)计算每个子节点的估价值,并为每个子节点配置指向父节点的指针,把这些子节点都送到OPEN表中,然后对OPEN表中的全部节点按估价值从小到大的顺序排列。

3、具体说明用A*算法求解传教士与野人问题。

M=C=5, K=3。

节点估价值设为f(n)=h(n)+g(n),g(n)设为节点搜索深度,而h(n)= m(n) + c(n) - 2b(n),其中m:河左岸的传教士人数;c:河左岸的野人人数;b:船是否在左岸,1:表示在左岸,0:表示不在左岸。

采用结构体定义形式,定义状态节点*NewNode(int m, int c, int b),其中包含m左岸传教士人数、c左岸野人人数、b船状态(左或右)。

开始状态为(3,3,1),目标状态为(0,0,0)。

若需要条件满足,即任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉,要对状态结点的安全性进行判断,判断一个状态是否为安全的,即是否满足在河的任何一岸,传教士人数不少于野人人数,或者只有野人而没有传教士。

对于超出参数范围的状态,也认为是不安全的。

即判断:if (pNode->m < 0 ||pNode->c < 0 ||pNode->m > M ||pNode->c > M) return 0;if (pNode->m == M ||pNode->m == 0) return 1;要扩展节点n生成其全部后继节点. 对于n的每一个后继节点m配置指向父节点的指针时:a)计算f(m)b)如果m既不在OPEN表中, 也不在CLOSED表中, 则用估价函数f把它添入OPEN表. 从m加一指向父辈节点n的指针。

c)如果m已在OPEN表或CLOSED表上, 则比较刚刚对m计算过的值f和前面计算过的该节点在表中的f值. 如果新的f值较小, 则I.以此新值取代旧值II.从m指向n, 而不是指向它的父辈节点III.如果节点m在CLOSED表中, 则把它移回OPEN表四、具体函数功能1)int Equal(struct NODE *pNode1, struct NODE *pNode2)功能:判断两个节点所表示的状态是否相等入口参数:pNode1:指向节点1的指针pNode2:指向节点2的指针返回值:当两个节点所表示的状态相等时,返回1,否则返回02)struct NODE *NewNode(int m, int c, int b)功能:动态产生一个节点,其状态值由参数m,c,b给定。

入口参数:m:河左岸的传教士人数c:河左岸的野人人数b:船是否在左岸,1:表示在左岸,0:表示不在左岸返回值:指向新产生的节点的指针,或者空间不够时,返回NULL 3)void FreeList(struct NODE *pList)功能:释放动态产生的链表入口参数:pList:指向OPEN表或者CLOSED表的指针返回值:无4)struct NODE *In(struct NODE *pNode, struct NODE *pList)功能:判断一个节点是否在一个链表中入口参数:pNode:指向给定节点的指针pList:指向给点链表的指针返回值:当pNode在pList中时,返回以pNode为首的链表的后一部分;否则返回NULL5)struct NODE *Del(struct NODE *pNode, struct NODE *pList)功能:从链表pList中删除节点pNode入口参数:pNode:指向给定节点的指针pList:指向给定的链表返回值:删除给定节点后的链表6)struct NODE *AddToOpen(struct NODE *pNode, struct NODE *pOpen)功能:将一个节点按照f值(从小到大)插入到OPEN表中入口参数:pNode: 指向给定节点的指针pOpen:指向OPEN表的指针返回值:指向插入给定节点后OPEN表的指针注意:同一个节点(具有相同指针的一个节点),只能向表中添加一次,否则可能会造成循环链表7)struct NODE *AddToClosed(struct NODE *pNode, struct NODE *pClosed)功能:将一个节点插入到CLOSED表中入口参数:pNode: 指向给定节点的指针pClosed:指向CLOSED表的指针返回值:指向插入给定节点后CLOSED表的指针注意:同一个节点(具有相同指针的一个节点),只能向表中添加一次,否则可能会造成循环链表8)void PrintList(struct NODE *pList)功能:在屏幕上打印一个链表,用于调试程序入口参数:pList:指向链表的指针返回值:无9)void PrintNode(struct NODE *pNode)功能:在屏幕上打印一个节点,用于调试程序入口参数:pNode:指向节点的指针返回值:无10)void PrintPath(struct NODE *pGoal)功能:在屏幕上打印解路径。

在搜索过程中,每个节点指向其父节点,从目标节点开始,逆向打印各节点,既得到解路径入口参数:pGoal:指向求解得到的目标节点返回值:无11)int IsGrandFather(struct NODE *pNode, struct NODE *pFather)功能:判断一个节点是否与自己的祖父节点所表示的状态一样入口参数:pNode:指向给定节点的指针pFather:指向给定节点的父节点的指针返回值:当给定节点所表示的状态与自己的祖父一样时,返回1,否则返回0 12)int IsGoal(struct NODE *pNode)功能:判断给定节点是否为目标节点入口参数:pNode:指向给定节点的指针返回值:当给定节点是目标节点时,返回1,否则返回013)int Safe(struct NODE *pNode)功能:判断一个状态是否为安全的,即是否满足在河的任何一岸,传教士人数不少于野人人数,或者只有野人而没有传教士。

对于超出参数范围的状态,也认为是不安全的入口参数:pNode:指向给定节点的指针返回值:当给定节点安全时,返回1,否则返回014)int H_Function(struct NODE *pNode)功能:计算给定节点的h值,h = m + c - 2b入口参数:pNode:指向给定节点的指针返回值:h值15)struct NODE *A_Star(struct NODE *s)功能:A*算法主函数入口参数:s:指向初始节点的指针返回值:指向求解得到的目标节点的指针,或者返回NULL表示空间不够用或者找不到问题的解五、程序源代码#define M 3 //传教士总人数#define C 3 //野人总人数#define K 2 //船一次可以乘坐的最多人数struct NODE{int m; //在左岸的传教士人数int c; //在左岸的野人人数int b; //b=1表示船在左岸,b=0表示船在右岸double g; //该节点的g值double f; //该节点的f值struct NODE *pFather; //指向该节点的父节点struct NODE *pNext; //在OPEN表或者CLOSED表中,指向下一个元素};struct NODE *g_pOpen = NULL; //全程变量,OPEN表struct NODE *g_pClosed = NULL; //全程变量,CLOSED表int Equal(struct NODE *pNode1, struct NODE *pNode2){if (pNode1->m == pNode2->m &&pNode1->c == pNode2->c &&pNode1->b == pNode2->b) return 1;else return 0;}struct NODE *NewNode(int m, int c, int b){struct NODE *pNode = NULL;pNode = malloc(sizeof(struct NODE));if (pNode == NULL) return NULL;pNode->m = m;pNode->c = c;pNode->b = b;pNode->g = 0;pNode->f = 0;pNode->pFather = NULL;pNode->pNext = NULL;return pNode;}void FreeList(struct NODE *pList){struct NODE *pNode = NULL;while (pList){pNode = pList;pList = pList->pNext;free(pNode);}}struct NODE *In(struct NODE *pNode, struct NODE *pList){if (pList == NULL) return NULL;if (Equal(pNode, pList)) return pList;return In(pNode, pList->pNext);}struct NODE *Del(struct NODE *pNode, struct NODE *pList){if (pList == NULL) return pList;if (Equal(pNode, pList)) return pList->pNext;pList->pNext = Del(pNode, pList->pNext);return pList;}struct NODE *AddToOpen(struct NODE *pNode, struct NODE *pOpen) {if (pOpen == NULL) //OPEN表为空{pNode -> pNext = NULL;return pNode;}if (pNode->f < pOpen->f) //给定节点的f值小于OPEN表第一个节点的f值{pNode->pNext = pOpen; //插入到OPEN的最前面return pNode;}pOpen->pNext = AddToOpen(pNode, pOpen->pNext); //递归return pOpen;}struct NODE *AddToClosed(struct NODE *pNode, struct NODE *pClosed){pNode->pNext = pClosed;return pNode;}void PrintList(struct NODE *pList){while (pList) //依次打印链表{printf("((%d %d %d) %f %f)\n", pList->m, pList->c, pList->b, pList->g, pList->f);pList = pList->pNext;}}void PrintNode(struct NODE *pNode){printf("((%d %d %d) %f %f)\n", pNode->m, pNode->c, pNode->b, pNode->g, pNode->f);}void PrintPath(struct NODE *pGoal){if (pGoal == NULL) return;PrintPath(pGoal->pFather); //递归printf("(%d %d %d)\n", pGoal->m, pGoal->c, pGoal->b);}int IsGrandFather(struct NODE *pNode, struct NODE *pFather){if (pFather == NULL) return 0;if (pFather->pFather == NULL) return 0;return Equal(pNode, pFather->pFather);}int IsGoal(struct NODE *pNode){if (pNode->m == 0 &&pNode->c == 0 &&pNode->b == 0) return 1;else return 0;}int Safe(struct NODE *pNode){if (pNode->m < 0 ||pNode->c < 0 ||pNode->m > M ||pNode->c > M) return 0;if (pNode->m == M ||pNode->m == 0) return 1;return (pNode->m == pNode->c);}int H_Function(struct NODE *pNode){return pNode->m + pNode->c - 2*pNode->b;}struct NODE *A_Star(struct NODE *s){struct NODE *n = NULL, *m = NULL, *pNode = NULL;int i, j;g_pOpen = s; //初始化OPEN表和CLOSED表g_pClosed = NULL;while (g_pOpen) //OPEN表不空{n = g_pOpen; //取出OPEN表的第一个元素nif (IsGoal(n)) return n; //如果n为目标节点,则成功结束g_pOpen = g_pOpen->pNext; //否则,从OPEN表中删除ng_pClosed = AddToClosed(n, g_pClosed); //将n加入到CLOSED中// 以下两重循环,i表示上船的传教士人数,j表示上船的野人人数for (i = 0; i <= K; i++){for (j = 0; j <= K; j++){if (i + j == 0 || //非法的上船组合i + j > K ||(i != 0 && i < j)) continue;if (n->b == 1) //当船在左岸时{m = NewNode(n->m-i, n->c-j, 0); //产生下一个状态m}else //当船在右岸时{m = NewNode(n->m+i, n->c+j, 1); //产生下一个状态m }if (m == NULL) return NULL; //如果空间不够用,则失败结束if (IsGrandFather(m, n) || !Safe(m)) {free(m);continue;}m->pFather = n; //标记其父节点为nm->g = n->g + 1; //其g值为其父节点的g值加1m->f = m->g + H_Function(m); //计算其f值,f = g+hif (pNode = In(m, g_pOpen)) //如果m已经出现在OPEN表中{if (m->f < pNode->f) //如果m的f值小于OPEN表中相同状态的f值{//则将该节点从OPEN表中删除,并将m加入到OPEN 表中。

相关文档
最新文档