人工智能课程实验·过河问题/实验一 知识表示方法
注:在校计算机学生一名,菜鸟一枚,这是人工智能这门课的课程实验,以此做记录
实验一 知识表示方法
1.实验目的
(1)了解知识表示相关技术;
(2)掌握状态空间法的分析方法。
2.实验内容
状态空间法实验。从前有一条河,河的左岸有m(=3)个传教士、m(=3)个野人和一艘最多可乘n(=2)人的小船。约定左岸,右岸和船上或者没有传教士,或者野人数量不超过传教士,否则野人会把传教士吃掉。搜索一条可使所有的野人和传教士安全渡到右岸的方案。
(1)简述实验原理及方法,并请给出程序设计流程图。
本次试验选择传教士过河问题,以状态空间法实现。
解答步骤如下:
1) 设置状态变量并确定值域
M为传教士人数,C 为野人人数,B为船数,要求M>=C且M,C <= 3,L表示左岸,R表示右岸。
2) 确定状态组,分别列出初始状态集和目标状态集
用三元组来表示 :(ML , CL , BL)(均为左岸状态)其中0<=ML<=3 ,0<=CL<=0 ,BL ∈{ 0 , 1}
S0 :(3 , 3 , 1) —–> Sg: (0 , 0 , 0)
初始状态表示全部成员在河的的左岸;
目标状态表示全部成员从河的左岸全部渡河完毕。
3) 定义并确定规则集合
仍然以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij操作。其中,第一下标i表示船载的传教士数,第二下标j表示船载的食人者数;同理,从右岸将船划回左岸称之为Qij操作,下标的定义同前。则共有10种操作,操作集为
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 )
P20 if ( ML ,CL , BL=1 ) then ( ML–2 , CL , BL –1 )
P02 if ( ML ,CL , BL=1 ) then ( ML , CL–2 , BL –1 )
Q10 if ( ML ,CL , BL=0 ) then ( ML+1 , CL , BL+1 )
Q01 if ( ML ,CL , BL=0 ) then ( ML , CL+1 , BL +1 )
Q11 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 )
Q02 if ( ML ,CL , BL=0 ) then ( ML , CL +2, BL +1 )
4) 当状态数量不是很大时,画出合理的状态空间图
箭头旁边所标的数字表示了P或Q操作的下标,即分别表示船载的传教士数和食人者数。
接下来进行树的遍历,根据规则由根(初始状态)扩展出整颗树,检测每个结点的“可扩展标记”,为“-1”的即目标结点。由目标结点上溯出路径。(自己写的时候不是按照老师给的方法写的,直接用了深度优先搜索)
代码是用Python写的,因为最近在学Python
'''-----------------------
-实验1-过河问题V1.3 Python-
-------©TyxMaek-----------
-----------------------'''
import time #用于记录程序运行时间
Path = [] #记录可行路径
m,c,bn=0,0,0 #m传教士人数,c野人数,bn船上能乘坐的人数
Path_num=0 #记录可行路径条数
'''----------------------------------------------------
函数名称:isok函数
函数功能:用于判断当前状态是否合法
input:tm,tc,tn
return:可行返回True同时将状态写进Path中,否则返回False
----------------------------------------------------'''
def isok(tm,tc,tn):
#保证数值不回越界
if tm<0 or tm>m or tc<0 or tc>c:
return False
#保证在左岸和右岸的传教士和野人的数量满足题目条件
elif (tmand tm>0 and tc>0) or ((m-tm)<(c-tc) and m-tm>0 and c-tc>0):
return False
#若该状态已经在之前出现过则无需往下搜索
elif (tm,tc,tn) in Path :
return False
else:
Path.append((tm,tc,tn))#可行写入Path中
return True
'''----------------------------------------------------
函数名称:tryto函数
函数功能:深度优先搜索寻找可行路径递归
input:mm,cc,nn
return:有路径返回True并且输出路径,否则返回False
----------------------------------------------------'''
def tryto(mm,cc,nn):
tm,tc,tn=mm,cc,nn
#最终状态
if mm==0 and cc==0 and nn==0:
global Path_num
Path_num+=1
print("第{}条路:".format(Path_num))
print(Path)
return True
#递归
if nn==1:
for x in range(bn+1):
for y in range(bn+1):
if x + y >= 1 and x + y <= bn and (x>=y or x==0 or y==0):
#船上要满足传教士大于等于野人或者没有传教士的情况
tm,tc,tn=mm-x,cc-y,nn-1
if isok(tm,tc,tn)==True:
tryto(tm,tc,tn)#深度递归
Path.pop(Path.index((tm,tc,tn)))#将该状态从Path中弹出
else:
for x in range(bn+1):
for y in range(bn+1):
if x + y >= 1 and x + y <= bn and (x>=y or x==0 or y==0):
tm,tc,tn=mm+x,cc+y,nn+1
if isok(tm,tc,tn)==True:
tryto(tm,tc,tn)
Path.pop(Path.index((tm,tc,tn)))
return False
'''----------------------------------------------------
函数名称:main函数
函数功能:主函数
input:None
return:None
----------------------------------------------------'''
def main():
#输入
global m,c,bn
m=int(input("请输入传教士人数m:"))
c=int(input("请输入野人人数c:"))
bn=int(input("请输入船上可乘坐的人数n:"))
#将第一个状态写入Path
Path.append((m,c,1))
T_start=time.clock()#开始时间
if m>=c:#如果初始时传教士就比野人少则无需执行tryto()函数
tryto(m,c,1)
if Path_num==0:#如果Path_num=0则输出没有可行路径
print("没有可行路径!")
T_end=time.clock()#结束时间
Time=T_end-T_start#路径搜索所用时间
print("\n程序运行所用时间{}秒".format(Time))
input()
#开始执行程序
main()
#end by ©TyxMaek
这个代码个人认为可以更佳精简一些,而且深度优先可能会超出最深递归深度,所以想看看各位大佬有什么其他的方式方法可以解决这个问题更好的实现,还请不令赐教,十分感谢。