修道士与野人问题教学文案
2.2.3 知识表示与问题求解(状态空间法)

2.2.3 状态空间法
2.2.3.1 问题状态空间的构成
2. 算符
•算符:引起状态中某些变量发生变化,从而使问
题由一个状态变为另一个状态的操作。
•算符可分为走步、过程、规则、数学算子、运算
符号、逻辑符号等。
•例如:在产生式系统中,每一条产生式规则就是
一个算符;而在下棋程序中,一个算符就是一个 走步。
时,世界的末日就来临了。
自动化系仪自教研室 14
2.2.3 状态空间法 Hanoi塔
19世纪,法国的一位数学家 Édouard Lucas (1842−1891) 对该课 题进行过研究,他指示,要完成这 个任务,僧侣们搬动金盘的总次数: 18446744073709551615(20位)假 设僧侣们个个身强力壮,每天24小 时不知头疲倦地工作,而且一秒钟 移动一个金盘,那么,完成这个任 务也得花5800亿年。
自动化系仪自教研室
21
2.2.3 状态空间法 在状态空间图中,从初始节点(1,1)(状态S0)到目 标节点(3,3)(状态S8)的任何一条通路都是问题的 一个解。 最短的路径长度是3,它由3个算符组成:A(1,2)、 B(1,3)、A(2,3)。
自动化系仪自教研室
22
2.2.3 状态空间法
问题的初始状态集合为S={S0},目标状态集合为 G={S8}。 自动化系仪自教研室
18
2.2.3 状态空间法
自动化系仪自教研室
19
2.2.3 状态空间法 ③定义一组算符F 算符A(i,j)表示把盘子A从第i号柱子移到第j号柱 子上的操作; 算符B(i,j)表示把盘子B从第i号柱子移到第j号柱 子上的操作。 算符组F中共有12个算符:
人工智能试题及答案

人工智能试题及答案【篇一:人工智能经典试题及答案】ass=txt>2.8 设有如下语句,请用相应的谓词公式分别把他们表示出来:s(1) 有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花。
解:定义谓词dp(x):x是人l(x,y):x喜欢y其中,y的个体域是{梅花,菊花}。
将知识用谓词表示为:(?x )(p(x)→l(x, 梅花)∨l(x, 菊花)∨l(x, 梅花)∧l(x, 菊花))(2) 有人每天下午都去打篮球。
解:定义谓词p(x):x是人b(x):x打篮球a(y):y是下午将知识用谓词表示为:a(?x )(?y) (a(y)→b(x)∧p(x))(3) 新型计算机速度又快,存储容量又大。
解:定义谓词nc(x):x是新型计算机f(x):x速度快b(x):x容量大将知识用谓词表示为:(?x) (nc(x)→f(x)∧b(x))(4) 不是每个计算机系的学生都喜欢在计算机上编程序。
解:定义谓词s(x):x是计算机系学生l(x, pragramming):x喜欢编程序u(x,computer):x使用计算机将知识用谓词表示为:? (?x) (s(x)→l(x, pragramming)∧u(x,computer))(5) 凡是喜欢编程序的人都喜欢计算机。
解:定义谓词p(x):x是人l(x, y):x喜欢y将知识用谓词表示为:(?x) (p(x)∧l(x,pragramming)→l(x, computer))2.9 用谓词表示法求解机器人摞积木问题。
设机器人有一只机械手,要处理的世界有一张桌子,桌上可堆放若干相同的方积木块。
机械手有4个操作积木的典型动作:从桌上拣起一块积木;将手中的积木放到桌之上;在积木上再摞上一块积木;从积木上面拣起一块积木。
积木世界的布局如下图所示。
图机器人摞积木问题解:(1) 先定义描述状态的谓词clear(x):积木x上面是空的。
(x, y):积木x在积木y的上面。
人工智能:野人与修道士问题

野人与修道士问题(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}是终⽌状态图。
人工智能教程习题及答案第2章习题参考解答

第二章知识表示习题参考解答2.3 练习题2.1 什么是知识?它有哪些特性?有哪几种分类方法?2.2 何谓知识表示? 陈述性知识表示法与过程性知识表示法的区别是什么?2.3 在选择知识的表示方法时,应该考虑哪些主要因素?2.4 一阶谓词逻辑表示法适合于表示哪种类型的知识?它有哪些特点?2.5 请写出用一阶谓词逻辑表示法表示知识的步骤。
2.6 设有下列语句,请用相应的谓词公式把它们表示出来:(1)有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花。
(2)他每天下午都去玩足球。
(3)太原市的夏天既干燥又炎热。
(4)所有人都有饭吃。
(5)喜欢玩篮球的人必喜欢玩排球。
(6)要想出国留学,必须通过外语考试。
2.7 房内有一只猴子、一个箱子,天花板上挂了一串香蕉,其位置关系如图2. 11所示,猴子为了拿到香蕉,它必须把箱子推到香蕉下面,然后再爬到箱子上。
请定义必要的谓词,写出问题的初始状态(即图2.16所示的状态)、目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。
图2.11 猴子摘香蕉问题2.8 对习题2.7中的猴子摘香蕉问题,利用一阶谓词逻辑表述一个行动规划,使问题从初始状态变化到目标状态。
2.9 产生式的基本形式是什么?它与谓词逻辑中的蕴含式有什么共同处及不同处?2.10 何谓产生式系统?它由哪几部分组成?2.11 产生式系统中,推理机的推理方式有哪几种?在产生式推理过程中,如果发生策略冲突,如何解决?2.12 设有下列八数码难题:在一个3×3的方框内放有8个编号的小方块,紧邻空位的小方块可以移入到空位上,通过平移小方块可将某一布局变换为另一布局(如图2.12所示)。
请用产生式规则表示移动小方块的操作。
2831231684754765S0S g图2.12 习题2.12的图图2.13 习题2.13的图2.13 推销员旅行问题:设有五个相互可直达且距离已知的城市A、B、C、D、E,如图2.13所示,推销员从城市A出发,去其它四城市各旅行一次,最后再回到城市A,请找出一条最短的旅行路线。
人工智能教程习题及答案第2章习题参考解答

第二章知识表示习题参考解答2.3 练习题2.1 什么是知识?它有哪些特性?有哪几种分类方法?2.2 何谓知识表示? 陈述性知识表示法与过程性知识表示法的区别是什么?2.3 在选择知识的表示方法时,应该考虑哪些主要因素?2.4 一阶谓词逻辑表示法适合于表示哪种类型的知识?它有哪些特点?2.5 请写出用一阶谓词逻辑表示法表示知识的步骤。
2.6 设有下列语句,请用相应的谓词公式把它们表示出来:(1)有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花。
(2)他每天下午都去玩足球。
(3)太原市的夏天既干燥又炎热。
(4)所有人都有饭吃。
(5)喜欢玩篮球的人必喜欢玩排球。
(6)要想出国留学,必须通过外语考试。
2.7 房内有一只猴子、一个箱子,天花板上挂了一串香蕉,其位置关系如图2. 11所示,猴子为了拿到香蕉,它必须把箱子推到香蕉下面,然后再爬到箱子上。
请定义必要的谓词,写出问题的初始状态(即图2.16所示的状态)、目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。
图2.11 猴子摘香蕉问题2.8 对习题2.7中的猴子摘香蕉问题,利用一阶谓词逻辑表述一个行动规划,使问题从初始状态变化到目标状态。
2.9 产生式的基本形式是什么?它与谓词逻辑中的蕴含式有什么共同处及不同处?2.10 何谓产生式系统?它由哪几部分组成?2.11 产生式系统中,推理机的推理方式有哪几种?在产生式推理过程中,如果发生策略冲突,如何解决?2.12 设有下列八数码难题:在一个3×3的方框内放有8个编号的小方块,紧邻空位的小方块可以移入到空位上,通过平移小方块可将某一布局变换为另一布局(如图2.12所示)。
请用产生式规则表示移动小方块的操作。
2831231684754765S0S g图2.12 习题2.12的图图2.13 习题2.13的图2.13 推销员旅行问题:设有五个相互可直达且距离已知的城市A、B、C、D、E,如图2.13所示,推销员从城市A出发,去其它四城市各旅行一次,最后再回到城市A,请找出一条最短的旅行路线。
AI总结

1、数据、信息和知识(1)数据是信息的载体; (2)信息是数据的解释 (3)知识是关联的信息;(4)元知识是使用知识的知识。
图1-1 知识的金字塔结构2.知识的特点:相对正确性,不确定性(获得的信息不完全),知识是可表达的(数据、文字、图形、公式等),可利用性(用来改造世界)。
3.知识的分类按知识的获得是否依赖于感觉器官来划分,知识可分为先验知识和后验知识。
先验知识不依赖于感觉器官,一般是正确的; 后验知识依赖于感觉器官,是相对正确的。
按知识的作用分为说明性知识、过程性知识、控制性知识。
说明性知识:一般陈述句, “是什么”; 过程性知识:如何去做某事;控制性知识:相当于元知识,如何决定去做某事。
按知识的作用范围可分为常识性知识和领域性知识。
按确定性可分为确定性知识和不确定性知识。
按人类思维方式和知识的结构及表现形式分为逻辑性知识和形象性知识。
4、知识表示知识表示技术研究知识以什么样的形式表示才能便于在计算机中存储和处理。
知识表示是对人类知识的一种形式化描述;知识表示的过程就是把知识编码成计算机能处理的数据结构的过程; 知识表示是数据结构与控制结构的统一。
3、知识表示:知识表示是指知识在计算机中的表示方法和表示形式,它涉及到知识的逻辑结构和物理结构。
主要表示方法有:状态空间、语义网络、谓词逻辑、框架知识表示技术研究的要求:能否充分表示相关领域的知识; 是否是有利于对知识的利用;是否便于在计算机中的组织和管理; 是否便于理解和实现。
4、几种知识表示方法 1、状态空间法 2、产生式表示法 3、谓词逻辑表示法 4、语义网络表示法 5、框架表示法其它:面向对象表示、剧本表示、过程表示等。
元知识 知识 信息 数据 噪声1.2 状态空间表示法图1-2 水的状态转换图图1-3 气球的状态转换图 怎样描述状态及状态的改变 (1)状态状态是描述某一类事物中各事物之间的差异而引入的最少的一组变量。
的有序集合。
人工智能试题及答案

人工智能试题及答案【篇一:人工智能经典试题及答案】ass=txt>2.8 设有如下语句,请用相应的谓词公式分别把他们表示出来:s(1) 有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花。
解:定义谓词dp(x):x是人l(x,y):x喜欢y其中,y的个体域是{梅花,菊花}。
将知识用谓词表示为:(?x )(p(x)→l(x, 梅花)∨l(x, 菊花)∨l(x, 梅花)∧l(x, 菊花))(2) 有人每天下午都去打篮球。
解:定义谓词p(x):x是人b(x):x打篮球a(y):y是下午将知识用谓词表示为:a(?x )(?y) (a(y)→b(x)∧p(x))(3) 新型计算机速度又快,存储容量又大。
解:定义谓词nc(x):x是新型计算机f(x):x速度快b(x):x容量大将知识用谓词表示为:(?x) (nc(x)→f(x)∧b(x))(4) 不是每个计算机系的学生都喜欢在计算机上编程序。
解:定义谓词s(x):x是计算机系学生l(x, pragramming):x喜欢编程序u(x,computer):x使用计算机将知识用谓词表示为:? (?x) (s(x)→l(x, pragramming)∧u(x,computer))(5) 凡是喜欢编程序的人都喜欢计算机。
解:定义谓词p(x):x是人l(x, y):x喜欢y将知识用谓词表示为:(?x) (p(x)∧l(x,pragramming)→l(x, computer))2.9 用谓词表示法求解机器人摞积木问题。
设机器人有一只机械手,要处理的世界有一张桌子,桌上可堆放若干相同的方积木块。
机械手有4个操作积木的典型动作:从桌上拣起一块积木;将手中的积木放到桌之上;在积木上再摞上一块积木;从积木上面拣起一块积木。
积木世界的布局如下图所示。
图机器人摞积木问题解:(1) 先定义描述状态的谓词clear(x):积木x上面是空的。
(x, y):积木x在积木y的上面。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
修道士与野人问题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)数据结构设计逻辑结构设计: 图型结构存储结构设计: 链式存储结构采用这种数据结构的好处:便于采用广度搜索法,得到首先搜索到的边数最少的一条通路,输出一个最佳方案,采用图的邻接表存储结构搜索效率较高。
(2)算法设计算法设计的总体设计思路为:在得到修道士人数和小船的容纳人数后,用boatcase得到所有情况,然后再进行安全性检查,以减去修道士少于野人的情况,接着用孩子兄弟结点表示法,将去对面的路作为孩子结点,路与路是兄弟关系,到达另一边时,同样以这种方法,直到找到(0,0,0)。
主要分为4个模块:boatcase生成所有情况,BFS得到边数最少的最佳方案,safe安全性检测,print输出安全渡河的全过程。
各个模块要完成的主要功能分别为:生成模块:生成所有的可能渡河情况安全检测模块:对所有的可能渡河情况进行安全检测,,以减去修道士少于野人的情况广度搜索模块:采用广度搜索法,得到首先搜索到的边数最少的一条通路输出模块:输出所有安全渡河的全过程主程序的流程图:来进行初始化来插入结点2.2 设计表示(1)函数调用关系图(2)函数接口规格说明void Linkinit(Link **head)void insertson(Link *head, DataType x) void insertbro(Link *head,DataType x)int boatcase(DataType x,int n)void guangdu(Link *p,int n,int c)int safe(DataType x,int n)void print(Link *q,Link *p)2.3 详细设计➢生成模块int boatcase(DataType x,int n) {int i=0,a,b,t=0;if(x.cw) {a=0;b=n-a;while (a+b>=1){t++;while (b>=0){ array[i].xds=a;array[i].yr=b;i++;a++;b--;}a=0; b=n-a-t;}}else{a=1;b=0;t=0;while (a+b<=n){t++;while (a>=0){array[i].xds=a*(-1);array[i].yr=b*(-1);i++;a--;b++;}a=array[0].xds*(-1)+t;b=0;}}return i;}➢安全检测模块int safe(DataType x,int n){if((x.xds>=x.yr||x.xds==0)&&((n-x.xds)>=(n-x.yr)||x.xds==n)&&x.xds>=0&&x.xds<=n&&x.yr>=0&&x.yr<=n) return 1;elsereturn 0;}➢广度搜索模块void guangdu(Link *p,int n,int c){Link *q,*t;DataType tem;int i,flag1,flag2,g=0,j,count=0;q=p->son;while (q!=NULL)/{flag1=0;j=boatcase(q->data,c);for (i=0;i<j;i++) {tem.xds=q->data.xds-array[i].xds;tem.yr=q->data.yr-array[i].yr;tem.cw=1-q->data.cw;t=q;if (safe(tem,n)) {flag2=1;//1while (t!=p){if(tem.xds== t->data.xds&&tem.yr==t->data.yr&&tem.cw==t->data.cw){flag2=0;break;}t=t->par;}if(flag2==1){if (flag1==0){insertson(q, tem);flag1=1;}elseinsertbro(q,tem); if (tem.xds==0&&tem.yr==0&&tem.cw==0){print(q,p);count++;}}}}q=q->next;}if (count==0)printf("无法成功渡河!\n");elseprintf("有%d种渡河方式。
\n",count);}➢输出模块void print(Link *q,Link *p){DataType a[100];int i=1;a[0].cw=0;a[0].xds=0;a[0].yr=0;while (q!=p){a[i++]=q->data;q=q->par;}while ((--i)>-1){printf("( %d %d %d )",a[i].xds,a[i].yr,a[i].cw);if (!(a[i].xds==0&&a[i].yr==0&&a[i].cw==0)){if(a[i].cw==1)printf("-->(%d %d)-->(%d %d 0)\n",a[i].xds-a[i-1].xds,a[i].yr-a[i-1].yr,a[i-1].xds,a[i-1].yr);elseprintf(" <-- ( %d %d ) <-- ( %d %d1 )\n",(a[i].xds-a[i-1].xds)*(-1),(-1)*(a[i].yr-a[i-1].yr),a[i-1].xds,a[i-1].yr);}}printf("渡河成功!\n");}3.调试分析(1)本题是采用邻接表做为存储结构,将各种状态之间的迁移图保存下来,并用孩子兄弟表示法,以实现广度搜索;刚编好程序时出现死循环的现象,例如:带过去2个野人又带回来2个野人,在和其他同学讨论后,采用了2个标志位来避免出现死循环的现象,在进行运行的时候,曾出现了打印输出错误,经过一步一步调试,发现在插入结点的时候出现了插入错误,即没有考虑到pre 的改变,通过改正,重新运行检测,运行结果正确,在排版时通过一步步调试,参考了课本和老师的课件,并与和其他同学讨论后,终于通过调试和改正,,能够使输出结果很明显的渡河方案。
(2)可改进内容:显示表示哪些是渡河次数最短的,最佳渡河方案一共有几种,并输出每种最佳渡河方案,另外,可尝试用深度优先搜索算法来找最佳方案。
4.用户手册本程序在VC++6.0环境下运行,根据提示输入相应的渡河人数和小船能容纳的人数即可。
5.测试数据及测试结果测试用例1测试输入: n=3,c=2测试目的:检验程序运行时是否会陷入死循环正确输出:见截屏1,2实际输出:见截屏 3,4错误原因:未正确设置标志位,出现死循环现象当前状态:已改正截屏1截屏2截屏3截屏46.源程序清单#include <stdio.h>#include <malloc.h>#include <stdlib.h>typedef struct{int xds; //修道士个数int yr; //野人个数int cw; //船的位置}DataType;DataType array[50000];typedef struct node//结构体定义{DataType data;struct node *son;//儿子struct node *bro;//兄弟struct node *par;//双亲struct node *next;}Link;void Linkinit(Link **head) //初始化操作{*head=(Link *)malloc(sizeof (Link)); //申请动态空间(*head)->son=NULL;(*head)->bro=NULL;(*head)->par=NULL;(*head)->next=NULL;}void insertson(Link *head, DataType x) //在邻接表中插入儿子结点的操作{Link *q,*s;q=(Link *)malloc(sizeof (Link));q->data=x;head->son=q;//将x插入给头结点的儿子指针s=head;while (s->next!=NULL)s=s->next;q->par=head;q->son=NULL;q->bro=NULL;s->next=q;q->next=NULL;}void insertbro(Link *head,DataType x)//在邻接表中插入兄弟结点的操作, //所有的兄弟结点都指向他们右边的结点{Link *q,*s;q=(Link *)malloc(sizeof (Link));s=head->son;q->data=x;while (s->bro!=NULL)s=s->bro;s->bro=q;s->next=q;q->next=NULL;q->bro=NULL;q->par=head;q->son=NULL;}int boatcase(DataType x,int n) //生成所有情况;{int i=0,a,b,t=0;if(x.cw) //在此岸,上船的人多优先{a=0;b=n-a; //a为修道士b为野人while (a+b>=1)//当船上有人时{t++;while (b>=0)//当野人个数不为负数{array[i].xds=a;array[i].yr=b;i++;a++;b--;}a=0;//船上空位个数b=n-a-t;}}else//在对岸,上船的人少优先{a=1;b=0;t=0;while (a+b<=n){t++;//船上的人数while (a>=0){array[i].xds=a*(-1);array[i].yr=b*(-1);i++;a--;b++;}a=array[0].xds*(-1)+t;b=0;}}return i; //i为总数量}int safe(DataType x,int n)//安全性检测{ // 起始目的if ((x.xds>=x.yr||x.xds==0)&&((n-x.xds)>=(n-x.yr)||x.xds==n)&&x.xds>=0&&x.xds<=n&&x.yr>=0&&x.yr<=n)return 1;//船上修道士elsereturn 0;}void print(Link *q,Link *p) //打印安全渡河的过程,当船到对岸时,把对岸当作其始岸,此岸当作彼岸{DataType a[100];int i=1;a[0].cw=0;a[0].xds=0;a[0].yr=0;while (q!=p)//避免出现相同情况而循环{a[i++]=q->data;//将一次过河的情况给b[i]q=q->par;}while ((--i)>-1) //输出过河图{printf("( %d %d %d )",a[i].xds,a[i].yr,a[i].cw);if (!(a[i].xds==0&&a[i].yr==0&&a[i].cw==0)){if(a[i].cw==1)printf("-->(%d %d)-->(%d %d 0)\n",a[i].xds-a[i-1].xds,a[i].yr-a[i-1].yr,a[i-1].xds,a[i-1].yr);//a[i].xds-a[i-1].xds表示过河过程中船上的修道士数,a[i].yr-a[i-1].yr表示过河过程中船上的野人数elseprintf(" <-- ( %d %d ) <-- ( %d %d1 )\n",(a[i].xds-a[i-1].xds)*(-1),(-1)*(a[i].yr-a[i-1].yr),a[i-1].xds,a[i-1].yr);}}printf("渡河成功!\n");}void guangdu(Link *p,int n,int c)//广度搜索{Link *q,*t;DataType tem;int i,flag1,flag2,g=0,j,count=0;q=p->son;while (q!=NULL)//逐个搜索儿子结点{flag1=0;//等于0表示插入儿子结点,1表示插入兄弟结点j=boatcase(q->data,c);//可能过河的情况for (i=0;i<j;i++)//搜索兄弟结点{tem.xds=q->data.xds-array[i].xds;tem.yr=q->data.yr-array[i].yr;tem.cw=1-q->data.cw;t=q;if (safe(tem,n))//是否安全{flag2=1;//1表示没有死循环while (t!=p)//保证不会出现循环{if(tem.xds== t->data.xds&&tem.yr==t->data.yr&&tem.cw==t->data.cw){//出现相当情况时候flag2=0;break;}t=t->par;}if(flag2==1){if (flag1==0)//插入儿子结点{insertson(q, tem);flag1=1;}else//插入兄弟结点insertbro(q,tem); if (tem.xds==0&&tem.yr==0&&tem.cw==0){print(q,p);count++;}}}}q=q->next;}if (count==0)printf("无法成功渡河!\n");elseprintf("有%d种渡河方式。