一 题目要求:

设有m个传教士和n个野人来到河边,打算乘一只船从左岸渡到右岸去,该船每次最多载3人。在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。他们怎样才能用这条船安全地把所有人都渡河过去?试采用宽带优先和深度优先方法分析搜索过程。(说明:传教士和野人都会划船,测试:m=n=3)

二 构造状态空间:

这个题目的状态空间秒数为一组整数对(a,b,flag)。
a是左边岸上剩下的传教士数
b是左边岸上剩下的野人数目
flag取值为1时,船在左岸;flag取值为0是,船在右岸。
所以,初始状态为(m,n,1),目的状态为(0,0,0)。

三 对题目的理解:

可以想象到,这个题目应该采用树形结构来解,所以如何建立每个节点的数据结构就是难点。这里用Python写的算法,结点的数据结构如下:

class Point:def __init__(self, a, b, flag):self.a = a  # 左岸传教士数量self.b = b  # 左岸野人数量self.flag = flag  # flag = 1: 船在左岸;flag = 0: 船在右岸self.father = Noneself.node = [a, b, flag]

比较重要的是Point结点的father属性,指明了子节点与父节点的关系,保证了树形结构的准确性。

四 代码解释:

  1. 首先定义了传教士数目、野人数目、open表、closed表,声明了Point类,定义了初始节点init(3,3,3)和目的节点(0,0,0)。
  2. 在开始进行BFS算法或者DFS算法之前,先定义几个函数:
    1) safe:判断该节点内在左岸、右岸、船舶上的传教士数目是否大于野人数目或者有一方为0;
    2) equal:判断两个节点是否相同。这里防止组合“爆炸”(老师上课说的)或者说是死循环。这里是为了检测OPEN表和CLOSED表写的函数;
    3) back:判断该节点是否是父节点,防止节点重复;
    4) in_list:判断这个节点是否在某个表中。用来判断新生成的节点是否在OPEN表或者CLOSED表中。
  3. 开始编写BFS算法和DFS算法:
    1) 首先,先把初始节点init放入到OPEN表中,然后遍历OPEN表;
    2) 如果OPEN中取出的节点是目的节点goal,那么结束遍历;否则把这个节点从OPEN表取出,放入CLOUSED表;
    3) 然后根据此节点,来得到它的子节点,它的子节点要满足几个规则:符合题目规定的安全问题;不是父节点;不在OPEN表中;不在CLOUSED表中;
    4) 如果3的条件满足,那么把这个新节点放入OPEN表。深度优先和广度优先的区别在于,深度优先把新节点放在OPEN表的OPEN[0]位置,而广度优先把新节点放在OPEN表的末尾(这也是老师上课强调的)。
  4. 最后打印一下路径,就可显示出解。

五 算法输出分析:

1、 BFS宽度优先算法 结果分析
       如图1,是BFS算法打印出OPEN表的部分截图(太多了,就不全粘贴了),然后根据OPEN表可以写出宽度优先的遍历路径如图2。

图1-BFS算法结果

图2-BFS算法结果分析

2、 DFS宽度优先算法 结果分析
       如图3,是DFS算法打印出OPEN表的部分截图(太多了,就不全粘贴了),然后根据OPEN表可以写出深度优先的遍历路径如图4。

图3-DFS算法结果

图4-DFS算法结果分析

六 代码:

A = 3  # 传教士数量
B = 3  # 野人数量
K = 3  # 最大乘坐人数量
OPEN = []  # open表
CLOSED = []  # closed表class Point:def __init__(self, a, b, flag):self.a = a  # 左岸传教士数量self.b = b  # 左岸野人数量self.flag = flag  # flag = 1: 船在左岸;flag = 0: 船在右岸self.father = Noneself.node = [a, b, flag]init = Point(A, B, 1)  # 初始节点
goal = Point(0, 0, 0)  # 目标节点# 判断传教士是否安全def safe(s):if s.a > A or s.a < 0 or s.b > B or s.b < 0 or (s.a != 0 and s.a < s.b) or (s.a != A and A - s.a < B - s.b):return Falseelse:return Truedef equal(a, b):if a.node == b.node:return True# 判断当前状态与父状态是否一致
def back(new, s):if s.father is None:return Falsereturn equal(new, s.father)# 扩展节点时在open表和closed表中找原来是否存在相同mcb属性的节点
def in_list(new, l):for item in l:if new.node == item.node:return Truereturn Falsedef BFS(s):global OPEN, CLOSEDOPEN = [s]CLOSED = []while OPEN:  # open表非空get = OPEN[0]  # 取出open表第一个元素getif get.node == goal.node:  # 判断是否为目标节点return getOPEN.remove(get)  # 将get从open表移出CLOSED.append(get)  # 将get加入closed表# 以下得到一个get的新子节点new并考虑是否放入openfor i in range(A):  # 上船传教士for j in range(B):  # 上船野人# 船上非法情况if i + j == 0 or i + j > K or (i != 0 and i < j):continueif get.flag == 1:  # 当前船在左岸,下一状态统计船在右岸的情况new = Point(get.a - i, get.b - j, 0)else:  # 当前船在右岸,下一状态统计船在左岸的情况new = Point(get.a + i, get.b + j, 1)if not safe(new) or back(new, get):  # 状态非法或new折返了pass# 如果要拓展的节点满足以上情况,将它的父亲设为当前节点,计算f,并对open_list排序else:new.father = getif in_list(new, OPEN):passelif in_list(new, CLOSED):passelse:OPEN.append(new)print('OPEN表:')for o in OPEN:print(o.node)def DFS(s):global OPEN, CLOSEDOPEN = [s]CLOSED = []while OPEN:  # open表非空get = OPEN[0]  # 取出open表第一个元素getif get.node == goal.node:  # 判断是否为目标节点return getOPEN.remove(get)  # 将get从open表移出CLOSED.append(get)  # 将get加入closed表# 以下得到一个get的新子节点new并考虑是否放入openfor i in range(A):  # 上船传教士for j in range(B):  # 上船野人# 船上非法情况if i + j == 0 or i + j > K or (i != 0 and i < j):continueif get.flag == 1:  # 当前船在左岸,下一状态统计船在右岸的情况new = Point(get.a - i, get.b - j, 0)else:  # 当前船在右岸,下一状态统计船在左岸的情况new = Point(get.a + i, get.b + j, 1)if not safe(new) or back(new, get):  # 状态非法或new折返了pass # CHILD.pop()# 如果要拓展的节点满足以上情况,将它的父亲设为当前节点,计算f,并对open_list排序else:new.father = getif in_list(new, OPEN):passelif in_list(new, CLOSED):passelse:OPEN.insert(0,new)print('OPEN表:')for o in OPEN:print(o.node)# 递归打印路径
def printPath(f):if f is None:returnprintPath(f.father)# 注意print()语句放在递归调用前和递归调用后的区别。放在后实现了倒叙输出print(f.node)if __name__ == '__main__':final = DFS(init)if final:print('有解,解为:')printPath(final)else:print('无解!')

AI传教士和野人渡河问题-实验报告相关推荐

  1. 人工智能实验二——prolog语言求解渡河问题(传教士和野人渡河,农夫渡河问题)实现详解

    农夫渡河问题求解 这两个问题都是渡河问题,思路和方式是一样的:给出求解Prolog代码: 问题描述 一个农夫带着一匹狼.一只羊.一颗白菜要过河, 只有一条船而且 农夫每次最多只能带一个动物或物品过河, ...

  2. C语言版,传教士与野人渡河问题,使用深度优先搜索法求解(DFS),变态版,随便输入人数和船的最大载人数,人工智能经典题目,简单易懂,注释到位,没有bug

    目录 一.问题描述 二.迟来的代码 运行截图 三.简单分析 一.问题描述 有n个传教士和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯传教士,要求无论在何处,传教士的人数不得少于野人 ...

  3. AI A_star算法野人渡河-实验报告

    1. 问题描述及实验要求 请用A*算法实现野人过河问题,(1)分析设计估价函数f(2)采用C语言或Python编程实现(代码中适当加注释,输出具有可读性).        问题描述:设有m个传教士和n ...

  4. AI 八数码A_star算法问题-实验报告

    一 题目要求: 八数码问题的A星搜索算法实现         要求:设计估价函数,并采用c或python编程实现,以八数码为例演示A星算法的搜索过程,争取做到直观.清晰地演示算法,代码要适当加注释. ...

  5. python深度优先搜索传教士和野人_传教士和野人问题解题思路

    传教士和野人渡河问题 刘宪国050422023 野人过河问题描述如下:有三个传教士和三个野人过河,只有一条能装下两个人的船,在河的任何一方或者船上,如果野人的人数大于传教士的人数,那么传教士就会有危险 ...

  6. 人工智能实验报告 牧师与野人渡河 知识表示方法

    牧师与野人渡河问题 编译环境 Dev C++ 5.6.1 windows 10 实验要求 实验代码 #include<cstdio> #include<queue> #incl ...

  7. 野人与传教士——宽度优先搜索(完整报告,含全部代码)

    题目: 野人与传教士渡河问题:3个野人与3个传教士打算乘一条船到对岸去,该船一次最多能运2个人,在任何时候野人人数超过传教士人数,野人就会把传教士吃掉,如何用这条船把所有人安全的送到对岸?在实现基本程 ...

  8. 人工智能导论实验2——野人渡河黑白棋问题

    人工智能导论实验2--野人渡河&黑白棋问题 实验目的及要求: 本项目要求能够理解人工智能的基本原理,理解状态空间的概念.原理和方法,掌握用状态空间表示问题的步骤,掌握搜索方法的基本原理,并能够 ...

  9. 【C++】人工智能实验一 猴子摘香蕉/传教士与野人(含完整代码与状态迁移图)

    文章目录 一.猴子摘香蕉问题 1.问题描述 2.解题思路 3.实验结果及分析 实验结果一 实验结果二 实验结果三 4.实验结果 5.实验代码 二.传教士(牧师)与野人问题 1.问题描述 2.实验步骤 ...

最新文章

  1. git-【五】远程仓库
  2. java动态url_使用url Param的动态主题
  3. layui 单选框、复选框、下拉菜单 不显示问题 记录
  4. linux下动态链接库(.so)的显式调用和隐式调用
  5. 2021高考成绩查询截图,科目四2021模拟考试成绩截图
  6. Kotlin:数组、字符串模板
  7. ES6、7学习笔记(尚硅谷)-6-形参默认值的设置
  8. 单片机实验用c语言编写计算器,单片机实验报告计算器.doc
  9. 数据通信与计算机网络参考文献,通信工程论文参考文献
  10. vue 倒计时 插件_vue+moment实现倒计时效果
  11. js实现图片虚化_Web前端之高斯模糊图片记
  12. 对接支付宝网站支付接口
  13. 新手必看!如何在windows下安装Python(Python入门教程)
  14. 「高级java工程师」常见面试题及其答案(持续更新)
  15. 数据链路层的重点协议
  16. 卡那霉素(Kanamycin偶联卵清白蛋白 (KAN-OVA)
  17. 供应科研试剂Biotin-PEG-Thiol,Biotin-PEG-SH,生物素peg巯基
  18. 新手建站必看的十大忠告
  19. 云计算机能不能玩游戏,云电脑有哪些?可不可以拿来玩steam游戏?
  20. 内网linux 安装mysql

热门文章

  1. GROMACS运行参数整理(二)
  2. php 存储数据的方法,在PHP中存储可轻松编辑的配置数据的最快方法?
  3. R 语言常用操作与函数汇总
  4. 零基础入门学习Python(18)-全局变量与局部变量
  5. mSystem:西农韦革宏组细菌-真菌互作影响微生物多样性-土壤养分循环关系
  6. QIIME 2教程. 32如何写方法和引用Citing(2021.2)
  7. QIIME 2教程. 09数据导入Importing data(2020.11)
  8. eclipse取消不了多行注释_Eclipse常用快捷键
  9. arcgis 中label feature太长换行_MapGIS转换为ArcGIS小结
  10. R语言ggplot2可视化:在可视化图像中添加对角线(diagonal line)