人工智能导论实验指导书_第1页
人工智能导论实验指导书_第2页
人工智能导论实验指导书_第3页
人工智能导论实验指导书_第4页
人工智能导论实验指导书_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、实验一 基本的搜索技术【实验目的】通过运行演示程序,理解深度优先、广度优先、A*算法的原理和运行过程。【实验内容】1. 分别以深度优先、广度优先、A*算法为例演示搜索过程2. 观察运行过程记录搜索顺序3. 设置不同属性,观察和记录搜索过程的变化4. 分析不同算法的特点【实验原理】 在知识不完全时,一般不存在成熟的求解算法可以利用,只有利用已有的知识摸索前进,从许多可能的解中寻找真正的解这就是搜索。即使对于结构性能较好,理论上有算法可依的问题,由于问题本身的复杂性以及计算机在时间、空间上的局限性,往往也需要通过搜索来进行求解。 总的来说搜索策略分为两大类:盲目搜索和启发式搜索一、无信息的搜索策略

2、盲目搜索在不具有对特定问题的任何有关信息的条件下,按固定的步骤(依次或随即调用操作算子)进行的搜索,它能快速地运用一个操作算子。盲目搜索中,由于没有可参考的信息,因此只要能匹配的操作算子都须运用,这会搜索更多的状态。最重要的宽度优先和深度优先是最重要的盲目搜索方法。1. 宽度优先搜索:从根结点出发,按从低到高的层次顺序搜索,同一层的结点按固定的顺序(例如从左到右、从右到左)搜索。宽度优先总是先搜索到距离最近的目标结点。宽度优先搜索不适合用于分支较多的情况。2. 深度优先搜索:用回溯的思想搜索图。深度优先搜索适用于分支较多而层次较浅的情况。 二、利用知识引导搜索启发式搜索 盲目搜索复杂度很大,为

3、了提高算法效率,应该具体问题具体分析,利用与问题有关的信息,从中得到启发而来引导搜索,以达到减少搜索量的目的,这就是启发式搜索。 启发信息: (1) 陈述性启发信息:一般被用于更准确、更精炼地描述状态,使问题的状态空间缩小,如待求问题的特定状况等属于此类信息 (2) 过程性启发信息:一般被用于构造操作算子,使操作算子少而精 如一些规律性知识等属于此类信息 (3) 控制性启发信息:如何选择操作算子 控制性启发信息往往被反映在估价函数之中。估价函数的任务就是估计待搜索结点的“有希望”程度(或者说估计操作算子的“性能”),并依此给它们排定次序。估价一个结点的价值,必须综合考虑两方面的因素:已经付出的

4、代价(实际)和将要付出的代价(估计) f (n) = g (n) + h (n) 采用这种估价函数的搜索叫A搜索。令h*(n)为n到目的结点的实际最小代价,如果对任意节点n均有h(n)h*(n),则此时的A算法为A*算法。 如某一问题有解,那么利用A*搜索算法对该问题进行搜索则一定能搜索到解,并且一定能搜索到最优的解而结束。这三种搜索算法都使用了两张表来记录状态信息:在open表中保留所有已生成而子状态未扩展的状态;在closed表中记录已扩展过子状态的状态。广度优先搜索算法中的open表采用的是先进先出的“队列”。深度优先搜索算法中的open表采用的是后进先出的“栈”。启发式搜索算法中的op

5、en表中的元素是按启发估价函数值的大小排列的一个表,每次从表中优先取出启发估价函数值最小的状态加以扩展。同时并不丢弃其它的状态,而把它们保留在open表中。【实验步骤】1. 浏览器打开下面网址,单击“Start Applet”按钮进入演示系统/jpkc/rengongzhineng/rengongzhineng/search/search.html图1 演示系统图22. 单击主菜单中“File”“Load Sample Graph”,载入一个例子(例如“简单搜索树”),如图2红色椭圆标注,激活左侧“create”卡,鼠标指针指向右侧图中的结点或边,右击弹

6、出菜单,单击“Properties”(即属性),可以查看或修改结点或边的属性。结点的heuristics属性表示结点的启发值,边的Edge cost属性表示边的代价。(A*算法中结点的估价函数值为从开始结点到该结点所有边的代价和再加上该结点的启发值。SABb85553图3 如图3所示B的估价值为13。)3. 查看并记录所有结点的启发值和边的代价。4. 激活左侧的“Solved”卡,如图4红色椭圆标注图45. 单击主菜单中“Search Algorithms”,分别选定“Depth First”、“Breadth First”、“A*”。重复单击左侧“Step”按钮(图4蓝色椭圆标注),直到右侧

7、图中所有结点访问完毕。记录访问的结点顺序,并与自己预测的深度优先、宽度优先、A*的搜索顺序比较。(注:运行过程中红色的结点保存于closed表中,绿色的结点保存于open表中,蓝色的结点表示新展开的结点)6. 单击主菜单中“File”“Create new Graph”,激活左侧“create”卡,新建一个图。分别选定“Depth First”、“Breadth First”、“A*”,进行搜索,记录搜索顺序,并与自己预测的深度优先、宽度优先、A*的搜索顺序比较。S(4)A(6)B(4)C(6)D(5)E(5)F(5)G(6)H(6)I(5)J(7)K(5)L(5)M(7)实验二 传教士和野人

8、问题【实验目的】 通过具体问题的编程求解,了解人工智能的基本解决方法;使用一种搜索策略,以加深理解。【实验内容】设在河的一岸有三个野人、三个传教士和一条船,要用这条船把所有的人运到河对岸,但受以下条件的约束:(1) 传教士和野人都会划船,但每次船上至多可载两个人;(2) 二是在河的任一岸,如果野人数目超过修道士数,传教士会被野人吃掉。(3) 如果野人会服从任何一次过河安排编程实现一个确保传教士和野人都能过河,且没有传教士被野人吃掉的安全过河计划。【实验原理】 传教士和野人问题是一个经典的智力游戏问题。有N个传教士和N个野人来到河边准备渡河,河岸(甲岸和乙岸)有一条船,每次至多可供k人乘渡。应如

9、何规划摆渡方案,使得任何时刻,在河的两岸以及船上的野人数目总是不超过传教士的数目。即求解传教士和野人从左岸全部摆渡到右岸的过程中,任何时刻满足M(传教士数)C(野人数)和MCk的摆渡方案。设N3,k2,则给定的问题可用下图表示,图中L和R表示左岸和右岸,B1或0分别表示有船或无船。约束条件是:两岸上MC,船上MC2图1 MC问题实例简单的分析,总共有10种可能的操作:两个野人过河(从甲到乙,从乙到甲)两个传教士过河从(从甲到乙,从乙到甲)一个传教士和一个野人过河(从甲到乙,从乙到甲)一个野人过河(从甲到乙,从乙到甲)一个传教士过河(从甲到乙,从乙到甲)但对于一个具体状态,只有5种可能的操作(从

10、甲到乙或从乙到甲)。 先来看看问题的初始状态和目标状态,假设和分为甲岸和乙岸: 初始状态:甲岸,3野人,3牧师; 乙岸,0野人,0牧师; 船停在甲岸,船上有0个人; 目标状态:甲岸,0野人,0牧师; 乙岸,3野人,3牧师; 船停在乙岸,船上有0个人; 整个问题就抽象成了怎样从初始状态经中间的一系列状态达到目标状态。问题状态的改变是通过划船渡河来引发的,所以合理的渡河操作就成了通常所说的算符,根据题目要求,可以得出以下5个算符(按照渡船方向的不同,也可以理解为10个算符): 渡1野人、渡1牧师、渡1野人1牧师、渡2野人、渡2牧师 算符知道以后,剩下的核心问题就是搜索方法了,本文以深度优先搜索为基

11、础,通过一个FindNext()函数找出下一步可以进行的渡河操作,如果没有找到则返回其父节点,看看是否有其它兄弟节点可以扩展,然后用Process()函数递规调用FindNext(),一级一级的向后扩展。 搜索中的算符采用下面的规则固定排序,合理的排序能更快的搜索到较优的解: 甲岸一次运走的人越多越好(即甲岸运多人优先),同时野人优先运走;乙岸一次运走的人越少越好(即乙岸运少人优先),同时牧师优先运走; 同时注意下面两点:1. 不能重复上次渡船操作(通过链表中前一操作比较),避免进入死循环;2. 任何时候河两边的野人和牧师数均分别大于等于0且小于等于3;【实验过程】 设计程序求解传教士和野人问

12、题。附录C+程序及注释如下:/wildman.cpp#include iostream.htypedef struct _riverside / 岸边状态类型 int wildMan; / 野人数 int churchMan; / 牧师数RIVERSIDE;typedef struct _boat / 船的状态类型 int wildMan; / 野人数 int churchMan; / 牧师数 BOAT;typedef struct _question / 整个问题状态 RIVERSIDE riverSide1; / 甲岸 RIVERSIDE riverSide2; / 乙岸 int side

13、; / 船的位置, 甲岸为-1, 乙岸为1 BOAT boat; / 船的状态 _question* pPrev; / 指向前一渡船操作 _question* pNext; / 指向后一渡船操作QUESTION;/函数定义bool Process(QUESTION* pQuest);bool FindNext(QUESTION* pQuest);void VisitList(QUESTION* pQuest); /遍历链表输出结果/int main() / 初始化 QUESTION* pHead = new QUESTION; pHead-riverSide1.wildMan = 3; pHe

14、ad-riverSide1.churchMan = 3; pHead-riverSide2.wildMan = 0; pHead-riverSide2.churchMan = 0; pHead-side = -1; / 船在甲岸 pHead-pPrev = NULL; pHead-pNext = NULL; pHead-boat.wildMan = 0; pHead-boat.churchMan = 0; if (Process(pHead) cout成功渡河!endl; VisitList(pHead); else cout到底怎样才能渡河呢? 郁闷!pNext; delete pHead;

15、 pHead=pTemp; pHead = NULL; return 0;/ 渡船过程, 递归调用函数FindNext(.)bool Process(QUESTION* pQuest) if (FindNext(pQuest) QUESTION* pNew = new QUESTION; pNew-riverSide1.wildMan = pQuest-riverSide1.wildMan + pQuest-boat.wildMan*(pQuest-side); pNew-riverSide1.churchMan = pQuest-riverSide1.churchMan + pQuest-b

16、oat.churchMan*(pQuest-side); pNew-riverSide2.wildMan = 3 - pNew-riverSide1.wildMan; pNew-riverSide2.churchMan = 3 - pNew-riverSide1.churchMan; pNew-side = (-1)*pQuest-side; pNew-pPrev = pQuest; pNew-pNext = NULL; pNew-boat.wildMan = 0; pNew-boat.churchMan = 0; pQuest-pNext = pNew; if (pNew-riverSide

17、2.wildMan=3 & pNew-riverSide2.churchMan=3) return true; / 完成 return Process(pNew); else QUESTION* pPrev = pQuest-pPrev; if (pPrev = NULL) return false; / 无解 delete pQuest; pPrev-pNext = NULL; return Process(pPrev); / 返回其父节点重新再找 return true;/ 判断有否下一个渡河操作, 即根据比较算符找出可以接近目标节点的操作/ 算符共5个: 1野/ 1牧 / 1野1牧 /

18、2野 / 2牧 bool FindNext(QUESTION* pQuest) / 基本规则 / 渡船的优先顺序: 甲岸运多人优先, 野人优先; 乙岸运少人优先, 牧师优先. static BOAT boatState5; / 5个算符 if (pQuest-side = -1) boatState0.wildMan = 2; boatState0.churchMan = 0; boatState1.wildMan = 1; boatState1.churchMan = 1; boatState2.wildMan = 0; boatState2.churchMan = 2; boatState

19、3.wildMan = 1; boatState3.churchMan = 0; boatState4.wildMan = 0; boatState4.churchMan = 1; else boatState0.wildMan = 0; boatState0.churchMan = 1; boatState1.wildMan = 1; boatState1.churchMan = 0; boatState2.wildMan = 0; boatState2.churchMan = 2; boatState3.wildMan = 1; boatState3.churchMan = 1; boat

20、State4.wildMan = 2; boatState4.churchMan = 0; int i; / 用来控制算符 if (pQuest-boat.wildMan = 0 & pQuest-boat.churchMan = 0) / 初始状态, 第一次渡河时 i = 0; / 取算符1 else for (i=0; iboat.wildMan = boatStatei.wildMan & pQuest-boat.churchMan = boatStatei.churchMan) break; i+; if (i 5) int j; for (j=i; jriverSide1.wildM

21、an + boatStatej.wildMan * pQuest-side; int nChurchMan1 = pQuest-riverSide1.churchMan + boatStatej.churchMan * pQuest-side; int nWildMan2 = 3 - nWildMan1; int nChurchMan2 = 3 - nChurchMan1; / 判断本次操作的安全性, 即牧师数量=野人或牧师数为0 if (nWildMan1 = nChurchMan1 | nChurchMan1 = 0) & (nWildMan2 =0 & nChurchMan1 =0 &

22、nWildMan2 =0 & nChurchMan2 = 0) / 本操作是否重复上次操作,注意方向不同 if (pQuest-pPrev != NULL) if (pQuest-pPrev-boat.wildMan = boatStatej.wildMan & pQuest-pPrev-boat.churchMan = boatStatej.churchMan) continue; break; / 该操作可行, 推出循环 if (j boat.wildMan = boatStatej.wildMan; pQuest-boat.churchMan = boatStatej.churchMan

23、; return true; return false;/遍历链表输出结果void VisitList(QUESTION* pQuest)QUESTION* HD=pQuest;cout甲岸野人,传教士数量的变化:endl;while(HD!=NULL)coutriverSide1).wildMan,riverSide1.churchManpNext!=NULL) cout;HD=HD-pNext; cout8 4 7 5 7 6 5 Sg(0)其估价函数可以定义为:f(n) = d(n) + w(n) (1)其中d(n)代表状态的深度,每步为单位代价;w(n)表示以“不在位”的将牌数。 估价函数的另一个定义为: f(n) = d(n) + p(n) (2) 其中p(n) = 将牌“不在位”的距离和。采用这两种估价函数的A算法都是A*算法。附

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论