用python,以队列驱动搜索,写了代码。
整体思路如下:
用matplotlib绘制带有层级的点,代表搜索过程的状态,为这些点打上矩阵标签,就能得到良好的展示效果了。
(未带有标签)
(带有标签)
(如图,九宫格用0代表空位,初始状态为:[[2,8,3],[1,6,4],[7,0,5]],目标状态为[[1,2,3],[8,0,4],[7,6,5]])
(目标状态是一个顺时针的1-8)
要达到这样的展示效果,需要为matplotlib提供节点位置(x:由本层节点的个数及当前点在本层的位置决定,y:由节点的层次决定。),及对应该节点的矩阵标签。
open表/closed表存储了这样的一些节点:每个节点存储两个信息:矩阵、节点层级。
矩阵会发生改变,而节点层级又不唯一,字典要求键不改变且唯一,因此不能采用字典存储。
选择使用二元组存储。即(矩阵,层级)。
此处矩阵是二维列表。
进行主循环时,从open表头部取出节点,如果不在closed表中,则将其可能的后续节点加入open表,加入到头部是深度优先搜索,加入到尾部是宽度优先搜索。
这样,在同层级,不会出现重复的节点,但在不同层级,又允许矩阵相同的节点存在。
代码如下,笔者是新手,如果有误,还望见谅。
#人工智能引论作业:宽度优先搜索探索九宫格走法
#在最后一层的最后一个节点,达到了目标状态
#python==3.7.3
#matplotlib==3.1.0
#numpy==1.16.4
import matplotlib.pyplot as plt
import numpy as np
from copy import deepcopy as dp
#用于matplotlib正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#矩阵标签的像素大小。
lableSize=8
#获取0的位置,即空的位置
def getZeroPosition(twoArray):
for i in range(len(twoArray)):
for k in range(len(twoArray[i])):
if twoArray[i][k]==0:
return i,k
#进行0(空位置)与其他位置的交换:操作符/算子定义
def zeroUp(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x-1][zero_y]
myArray[zero_x-1][zero_y]=0
myArray[zero_x][zero_y]=t
def zeroDown(myArray):
zero_x,zero_y=getZeroPosition(myArray)
#print(zero_x,zero_y)
t=myArray[zero_x+1][zero_y]
myArray[zero_x+1][zero_y]=0
myArray[zero_x][zero_y]=t
def zeroRight(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x][zero_y+1]
myArray[zero_x][zero_y+1]=0
myArray[zero_x][zero_y]=t
def zeroLeft(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x][zero_y-1]
myArray[zero_x][zero_y-1]=0
myArray[zero_x][zero_y]=t
#初始状态
beginData=[[2,8,3],[1,6,4],[7,0,5]]
#目标状态
endData=[[1,2,3],[8,0,4],[7,6,5]]
#矩阵建立坐标系:坐标原点在矩阵的左上角,以纵向为x轴,横向为y轴。
#节点层次
level=1
#open表
lineList=[(beginData,level)]
#closed表
reList=[]
#主循环:open表不空
while lineList!=[]:
#避免同层次矩阵重复
if lineList[0] in reList:
del lineList[0]
continue
else:
#获得当前节点信息
thisArray=lineList[:][0][0]
level=lineList[0][1]
zero_x,zero_y=getZeroPosition(thisArray)
#进行4项可能移动,将新节点加入open表尾部
if zero_x!=2:
timely=dp(thisArray)
zeroDown(timely)
lineList.append((timely,level+1))
if zero_x!=0:
timely=dp(thisArray)
zeroUp(timely)
lineList.append((timely,level+1))
if zero_y!=2:
timely=dp(thisArray)
zeroRight(timely)
lineList.append((timely,level+1))
#reList.append((thisArray,level+1))
if zero_y!=0:
timely=dp(thisArray)
zeroLeft(timely)
lineList.append((timely,level+1))
#reList.append((thisArray,level+1))
#加入closed表
reList.append(lineList[0])
#目标状态判定
if lineList[0][0]==endData:
break
#print(lineList)
#删除当前节点
del lineList[0]
#两个函数用于得到合适的在图上显示的x坐标
def getXList(array):
oldLevel=1
times=0
xList=[]
for i in range(len(array)):
nowLevel=array[i][1]
if nowLevel==oldLevel:
times+=1
else:
xList.append(times)
times=1
oldLevel=nowLevel
xList.append(times)
return xList
def getXEList(array):
xEList=[]
for i in array:
for k in range(i):
xEList.append(20/(i+1)*(k+1))
return xEList
plt.xlim(xmax=22,xmin=0)
plt.ylim(ymax=7,ymin=0)
plt.xlabel('同层次节点个数 ')
plt.ylabel('层次')
t=getXList(reList)
#x,y存储节点位置,lable存储字符串化矩阵
x=getXEList(t)
y=[]
lable=[]
for i in reList:
y.append(7-i[1])
strArray=str(i[0])
lable.append(strArray[0:11]+'\n'+strArray[11:22]+'\n'+strArray[22:])
#lable.append("[1,3]")
#绘制节点
plt.scatter(x,y,s=3)
#为节点添加标签
for i in range(len(x)):
plt.annotate(lable[i],xy=(x[i],y[i]),size=lableSize)
plt.show()
#人工智能引论作业:深度优先搜索探索九宫格走法
#在最后一层的最后一个节点,达到了目标状态
#python==3.7.3
#matplotlib==3.1.0
#numpy==1.16.4
import matplotlib.pyplot as plt
import numpy as np
from copy import deepcopy as dp
#用于matplotlib正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#深度优先的最大深度
depth=6
#矩阵标签的像素大小
lableSize=8
#获取0的位置,即空的位置
def getZeroPosition(twoArray):
for i in range(len(twoArray)):
for k in range(len(twoArray[i])):
if twoArray[i][k]==0:
return i,k
#进行0(空位置)与其他位置的交换:操作符/算子定义
def zeroUp(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x-1][zero_y]
myArray[zero_x-1][zero_y]=0
myArray[zero_x][zero_y]=t
def zeroDown(myArray):
zero_x,zero_y=getZeroPosition(myArray)
#print(zero_x,zero_y)
t=myArray[zero_x+1][zero_y]
myArray[zero_x+1][zero_y]=0
myArray[zero_x][zero_y]=t
def zeroRight(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x][zero_y+1]
myArray[zero_x][zero_y+1]=0
myArray[zero_x][zero_y]=t
def zeroLeft(myArray):
zero_x,zero_y=getZeroPosition(myArray)
t=myArray[zero_x][zero_y-1]
myArray[zero_x][zero_y-1]=0
myArray[zero_x][zero_y]=t
#初始状态
beginData=[[2,8,3],[1,6,4],[7,0,5]]
#目标状态
endData=[[1,2,3],[8,0,4],[7,6,5]]
#矩阵建立坐标系:坐标原点在矩阵的左上角,以纵向为x轴,横向为y轴。
#节点层级
level=1
#open表,元素为二元组:(矩阵,层级)
lineList=[(beginData,level)]
#closed表
reList=[]
#仅存储矩阵的open表
arrayList=[]
#主循环:open表不为空
while lineList!=[]:
#避免同层次矩阵重复
if lineList[0][0] in arrayList:
del lineList[0]
#print(1)
continue
#深度优先,设置最大深度
elif lineList[0][1]>depth:
del lineList[0]
continue
else:
#将当前矩阵的所有可能的衍生节点都加入open表,要求进行4个可能移动时,矩阵不变
#深拷贝复制当前节点,避免列表/列表元素的改变
thisNode=dp(lineList[0])
thisArray=lineList[:][0][0]
#当前节点level
level=lineList[0][1]
#当前节点矩阵的0的坐标
zero_x,zero_y=getZeroPosition(thisArray)
#进行4项可能移动,将新节点插入open表头部
if zero_x!=2:
timely=dp(thisArray)
zeroDown(timely)
lineList.insert(0,(timely,level+1))
if zero_x!=0:
timely=dp(thisArray)
zeroUp(timely)
lineList.insert(0,(timely,level+1))
if zero_y!=2:
timely=dp(thisArray)
zeroRight(timely)
lineList.insert(0,(timely,level+1))
#reList.append((thisArray,level+1))
if zero_y!=0:
timely=dp(thisArray)
zeroLeft(timely)
lineList.insert(0,(timely,level+1))
#reList.append((thisArray,level+1))
#将当前节点加入closed表
reList.append(thisNode)
arrayList.append(thisNode[0])
#目标状态判定
if thisNode[0]==endData:
break
#移除当前节点
lineList.remove(thisNode)
#plt.xlim(xmax=28,xmin=0)
plt.ylim(ymax=7,ymin=0)
plt.xlabel('同层次节点个数')
plt.ylabel('节点层次')
#给每个节点合适的x坐标,便于显示,y坐标是其层次。
def getTheXEnd(array):
x=[]
times=[1,1,1,1,1,1]
for i in array:
for k in range(6):
if i[1]==k+1:
x.append(times[k]*5)
times[k]+=1
return x
#x,y存储节点位置,lable存储字符串化矩阵
x=getTheXEnd(reList)
y=[]
lable=[]
#得到y,将列表转化为矩阵。
for i in reList:
y.append(7-i[1])
strArray=str(i[0])
lable.append(strArray[0:11]+'\n'+strArray[11:22]+'\n'+strArray[22:])
#绘制散点
plt.scatter(x,y,s=10)
#为散点添加矩阵标签
for i in range(len(x)):
plt.annotate(lable[i],xy=(x[i],y[i]),size=lableSize)
plt.show()
无论是在搜索理论,还是在数据结构、python上,笔者都是新手,如果本篇文章出现谬误,恳请您在评论区指出。