人工智能实验指导书42+16学时Word下载.docx

上传人:b****8 文档编号:22860686 上传时间:2023-02-05 格式:DOCX 页数:16 大小:24.25KB
下载 相关 举报
人工智能实验指导书42+16学时Word下载.docx_第1页
第1页 / 共16页
人工智能实验指导书42+16学时Word下载.docx_第2页
第2页 / 共16页
人工智能实验指导书42+16学时Word下载.docx_第3页
第3页 / 共16页
人工智能实验指导书42+16学时Word下载.docx_第4页
第4页 / 共16页
人工智能实验指导书42+16学时Word下载.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

人工智能实验指导书42+16学时Word下载.docx

《人工智能实验指导书42+16学时Word下载.docx》由会员分享,可在线阅读,更多相关《人工智能实验指导书42+16学时Word下载.docx(16页珍藏版)》请在冰豆网上搜索。

人工智能实验指导书42+16学时Word下载.docx

4、选择Files项,打开下拉菜单,选择Load项,选择要打开的示例程序,选择Example1示例程序,再选择Edit项,可以进行编辑源程序。

5、编辑之后,可以选择Run项,执行程序,可以在Dialog窗口进行询问,即外部目标的执行,并分析程序之功能。

6、仿前例,运行Example11、Example15,分析程序功能。

7、退出,选择Quit项,可以退出TurboProlog程序,返回到Windows2000环境。

五、源程序

Example1:

domains

person,activity=symbol

predicates

likes(person,activity)

clauses

likes(ellen,tennis).

likes(john,football).

likes(tom,baseball).

likes(eric,swimming).

likes(mark,tennis).

likes(bill,X)iflikes(tom,X).

Example11:

domains

namelist=name*

name=symbol

member(name,namelist).

member(Name,[Name|_]).

member(Name,[_|Tail])ifmember(Name,Tail).

Example15:

father(name,name)

everybody

father(leonard,katherine).

father(carl,jason).

father(carl,marilyn).

everybodyif

father(X,Y),

write(X,"

is"

Y,"

'

sfather\n"

)andfail.

实验二N!

及Fibonacci序列问题(4学时)

掌握Turboprolog软件编程使用方法;

掌握Prolog程序的各域段含义;

初步学习分析、运用递归方法解决问题。

二、实验设备

三、实验内容及步骤

一)Fibonacci序列问题描述:

数字的Fibonacci序列是个正整数序列,序列头两个数均为1,其余数为其前两个数相加得到,该序列排列如下:

1,1,2,3,5,8,13,21,34,55……

Fibonacci序列通式为:

F1=1

F2=1

Fn=Fn-1+Fn-2

二)实验内容:

1、进一步熟悉Turboprolog的运行环境,程序调试的方法;

2、初步掌握递归原理,了解问题递归的详细过程。

3、理解递归停止条件对整个递归过程的作用。

4、写出求N!

及Fibonacci序列问题的Prolog程序。

三)实验步骤:

1、启动prolog编辑环境,编辑求N!

及Fibonacci序列源程序;

2、运行程序,分析结果;

3、尝试修改程序达到同样的目的。

实验三梵塔问题(4学时)

1、掌握PROLOG编制递归程序的方法:

边界条件与递归部分的设计;

2、掌握Prolog程序的各域段含义;

3、学会分析、运用递归方法解决问题。

1、分析汉诺塔问题,找出问题本身存在的递归性,编制程序;

2、显示汉诺塔问题中圆盘的移动次序;

3、归纳出圆盘数目与移动步骤之间的数学关系;

4、分析递归问题的实质。

一)问题描述:

如上图,目的是把左边的所有盘子移到右边的杆子上。

一次只能移动一个盘子,你可以使用中间的杆子作为临时存放盘子的地方。

在移动的过程中,小盘子必须放在大盘子之上。

二)分析问题:

如果盘子只有两三个,是很容易解决的。

但是随着盘子数目的增加,问题就变得非常难解了。

事实上,已经通过数学证明过了,最少的移动次数是2

,n为盘子的数目。

最早提出这个问题的人设定的盘子数目为64,这就是说需要2

=184********709551615次移动,假设计算机每秒钟能够计算10,000,000(一千万)次,那也需要58494年,所以你千万不要试图使用此程序来解较大的数。

让我们来看看如何用递归来解决这个问题:

如果只有一个盘子,直接移过去就行了,这是递归的边界条件。

如果要移动N个盘子,就要分三步走:

1、把N-1个盘子移动到中间的杆子上(把右边的杆子作为临时存放盘子的位置)。

2、把最后一个盘子直接移到右边的杆子上。

3、最后把中间杆子上的盘子移到右边的杆子上(把左边的杆子作为临时存放盘子的位置)。

上面第一、三步用到了递归。

我们看到,通过递归把N个盘子的问题变成了两个N-1个盘子的问题。

如此下去,最后就变成了2

个一个盘子的问题了,这也就是说问题被解决了。

三)实验内容:

1、分析汉诺塔问题,找出问题本身存在的递归性。

2、分析递归原理,熟悉问题递归的详细过程。

3、编写求梵塔问题的Prolog程序。

4、显示汉诺塔问题中圆盘的移动次序。

5、更改圆盘数量,了解问题解决的递归过程。

四)实验步骤:

1、启动prolog编辑环境,编辑hanoi源程序;

3、重复比较圆盘数目,根据其求解过程得到圆盘数量与步骤数目之间的规律。

归纳并理解问题递归的实质。

实验四渡河问题(4学时)

1、进一步掌握PROLOG编制递归程序的方法;

2、理解谓词show_move、state、unsafe在程序中的作用。

1、分析该问题的实质以及其中存在的递归作用;

2、利用列表数据结构编写出渡河问题的程序;

3、联系前面的全排列问题理解列表数据结构的作用。

4.1问题的引出

一个农夫带着他的狼、山羊和白菜要过河。

河边有一只小船,但这只小船一次只能同时带两件东西(包括农夫自己,他要划船)。

如果狼和山羊留在一起.则狼要吃掉山羊;

同理如果山羊和白菜留在一起,则山羊要吃掉白菜。

农夫要如何安排渡河的步骤,才能保证农夫、山羊、狼、白菜都能安全到达河的对岸。

二)分析问题及编写程序:

这个问题还可以扩展为N1个牧师和N2个野人,而船一次可以装下M个人的情况。

我们使用Prolog解决上面的问题。

 

这是个典型的状态图搜索问题,所以我们首先需要解决的问题就是使用Prolog的数据结构表达两岸的状态,以及对这些状态可能的操作。

我们用下面的复合结构来表达问题的某个状态。

((左岸牧师数,左岸野人数),(右岸牧师数,右岸野人数),船的位置) 

上面的结构中,船的位置为0表示船在左岸,为1表示在右岸。

一开始,所有的人都在左岸。

所以初始状态如下:

((3,3),(0,0),0) 

而我们的目标状态则是:

((0,0),(3,3),1) 

当然,这里只是为了方便起见,才使用了上面的结构,实际上是没有必要包括右岸的人数的,因为可以通过左岸的人数算出右岸的人数来。

不过我们这里所选用的数据结构也有其优点,它可以是程序更加容易理解。

船上所能够载人的状态就是可能的操作。

用谓词move/2表示。

move(1,0).表示船上有一位牧师,没有野人。

move(0,1). 

move(0,2). 

move(2,0). 

move(1,1). 

有了上面的表达状态的数据结构以及移动的方法,我们还需要判断状态是否合法。

下面的legal1就是完成这个任务。

legal((X,Y,_)):

%X为左岸状态,Y为右岸状态。

legal1(X), 

%分别判断两岸的状态是否合法。

legal1(Y). 

legal1((X,Y)):

X=:

=0,Y>

=0,!

%牧师人数为0,野人的人数大于0,合法。

Y=:

=0,X>

%野人人数为0,牧师的人数大于0,合法。

X>

=Y,X>

=0. 

%牧师数大于或等于野人数,且都大于0,合法。

下面是使用legal/1的几个例子:

?

legal(((3,3),(0,0),1)). 

yes 

legal(((0,3),(3,0),1)). 

legal(((2,3),(1,0),0)). 

no 

legal1只判断牧师与野人的人数是否会造成牧师受到伤害,而不判断左右岸的人数之和是否正确。

所以((2,1),(1,1),0)也是合法的状态。

不过不用担心,在我们后面的程序中会避免这种情况出现的。

下面的update/3谓词能够完成把合理的移动作用的某个状态上,从而到达新的状态。

update((X,Y,0),Move,Statu1):

%船在左岸时 

(A,B)=X, 

(C,D)=Y, 

(E,F)=Move, 

C1 

is 

C+E, 

D1 

D+F, 

A1 

A-E, 

B1 

B-F, 

Statu1=((A1,B1),(C1,D1),1). 

update((X,Y,1),Move,Statu1):

%船在右岸时 

C-E, 

D-F, 

A+E, 

B+F, 

Statu1=((A1,B1),(C1,D1),0). 

update(((3,3),(0,0),0),(1,1),X). 

(2,2),(1,1),1 

;

update(((0,0),(3,3),0),(1,1),X). 

(-1,-1),(4,4),1 

update(((1,2),(2,3),1),(3,4),X). 

(4,6),(-1,-1),0 

注意update只是简单地进行加减运算,它并不判断所得的新的状态是否合法。

有了以上的三个谓词move/2,update/3,legal/1我们就可以很容易的做出判断两个合法的状态相邻的谓词,当然,此谓词也可以用来寻找某个状态的相邻状态。

connect(Statu,Statu1):

move(X,Y), 

update(Statu,(X,Y),Statu1), 

legal(Statu1). 

这是非常符合逻辑的谓词。

我们来看看功能:

connect(((3,3),(0,0),0),X). 

一个野人与一个牧师过河 

(3,2),(0,1),1 

一个野人过河 

(3,1),(0,2),1 

两个野人过河 

再使用典型的深度搜索方法就可以找到答案了:

findroad(X,X,L,L).% 

递归的边界条件。

findroad(X,Y,L,L1):

L为储存的路由表。

connect(X,Z), 

not(member(Z,L)), 

X所连接的节点Z不在已经储存的路由表中。

findroad(Z,Y,[Z|L],L1). 

findroad(((0,0),(3,3),1),((3,3),(0,0),0),[((0,0),(3,3),1)],L). 

[((3,3),(0,0),0), 

((3,1),(0,2),1), 

((3,2),(0,1),0), 

((3,0),(0,3),1), 

((3,1),(0,2),0), 

((1,1),(2,2),1), 

((2,2),(1,1),0), 

((0,2),(3,1),1), 

((0,3),(3,0),0), 

((0,1),(3,2),1), 

((1,1),(2,2),0), 

((0,0),(3,3),1)] 

findroad/4的第三个参数是初始路由表,在此我们把终点状态放到其中,上面的findroad是从终点向起点寻找,由于是对称的,这并不影响结果。

使用广度搜索也能完成相同的任务:

findroad([],X,X). 

findroad(Moves,State,Crit):

findroad(PrMoves,State,NextState), 

not(member(NextState,PrMoves)), 

connect(NextState,Crit), 

append(PrMoves,[NextState],Moves). 

findroad(L,((3,3),(0,0),0),((0,0),(3,3),1)). 

L=[((3 

 

3) 

(0 

0) 

0), 

((2 

2) 

(1 

1) 

1), 

((3 

((1 

(2 

((0 

(3 

0)] 

好了,到此为止过河问题已经基本上解决了。

不过为了能够使用本程序分析一般情况,即牧师与野人的人数和船的载客量为其它值的情况,我们来稍微改写一下这个程序。

谓词insert_move(N),动态地向内存中加入船的载客量为N时,船上载客的所有可能情况。

我们可以试试借用谓词leagal(X,Y)来实现:

insert_move(N):

X+Y 

N, 

legal(X,Y), 

asserta(move(X,Y)). 

上面的asserta/1谓词把它的参数作为子句加入到内存中。

这个程序看似简洁,其实错了,为什么呢?

因为 

X+Y 

有无穷组解。

所以要用以下方法:

get_integer(L,H,X):

-L>

H,!

fail. 

get_integer(L,H,L). 

-L1 

L+1,get_integer(L1,H,X). 

insert_move0(N), 

insert_move1(N). 

insert_move0(0). 

%野人或牧师有一方人数为0,则另一方的人数可以是0--N. 

insert_move0(N):

asserta(move(N,0)), 

asserta(move(0,N)), 

N1 

N-1, 

insert_move0(N1). 

insert_move1(N):

-%人数都不为0时,则野人的人数不能多于牧师的人数,并且总人数不能多于N. 

get_integer(1,N,X), 

get_integer(X,N,Y), 

X+Y=<

N, 

asserta(move(Y,X)), 

fail. 

insert_move1(_). 

来试一下功能。

insert_move(3). 

move(X,Y). 

谓词insert_statu(N1,N2),动态地加入初始状态与目标状态,当然是N个牧师与N个野人的情况。

insert_statu(N1,N2):

asserta(inistatu(((N1,N2),(0,0),0))),

asserta(desstatu(((0,0),(N1,N2),1))). 

下面的谓词用来从内存中删除以上的动态信息。

el_move:

retract(move(X,Y)), 

del_move. 

del_stat:

retract(inistatu(X)), 

retract(desstatu(Y)),!

del_stat. 

这些谓词的第二个子句是为了保证谓词永远能够成功,以免再调用它们时出现问题。

最后我们再分别编写使用广度搜索与深度搜索的主程序。

widesolve(N1,N2,M):

del_move, 

del_stat, 

insert_move(M), 

insert_statu1,(N1,N2), 

inistatu(X), 

desstatu(Y), 

!

findroad(L,X,Y), 

writelist(L), 

nl. 

deepsolve(N1,N2,M):

insert_statu(N1,N2), 

desstatu(Y),!

 

findroad(Y,X,[Y],L), 

第一个参数为野人与牧师的人数,第二个参数为船的最大载人量。

它们分别调用findroad/3(广度搜索)findroad/4(深度搜索)来完成搜索任务。

(在Prolog中参数数目不同的谓词,是不同的谓词) 

我们在深度搜索中加入的截断,因为我们想通过deepsolve判断问题是否有解,而通过widesolve寻找出最优解,这是因为广度搜索先总是找出最短路径。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 其它课程

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1