一、实验目的
熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解 N数码难题,理解求解流程和搜索顺序。
二、实验内容
以8数码问题为例实现 A*算法的求解程序(编程语言不限,如Python等)要求设计两种不同的估价函数。
三、实验要求
1.设置相同的初始状态和目标状态,针对不同的估价函数,求得问题的解,比较它们对搜索算法性能的影响,包括扩展节点数等,填入下表。
下面以我做的实验为例:
初始状态:1 3 2 4 5 6 8 0 7 目的状态: 1 2 3 4 5 6 7 8 0
注:耗时在每个人的电脑上数据不同
实验结果如下表:
算法 | 启发函数h(n) | 搜索步数 | 生成节点数 | 耗时 |
宽度优先 | / | 19 | 106176 | 10126.424312591553ms |
A* | 不在位数 | 29 | 5739 | 574.6653079986572ms |
A* | 哈密尔顿距离 | 35 | 808 | 100.56138038635254ms |
下面给出三种情况的代码:
1、启发函数 /
import numpy as np
import time
class State:
def __init__(self, state, directionFlag=None, parent=None, f=0):
self.state = state
self.direction = ['up', 'down', 'right', 'left']
if directionFlag:
self.direction.remove(directionFlag)
self.parent = parent
self.f = f
def getDirection(self):
return self.direction
def setF(self, f):
self.f = f
return
# 打印结果
def showInfo(self):
for i in range(len(self.state)):
for j in range(len(self.state)):
print(self.state[i, j], end=' ')
print("\n")
print('->')
return
# 获取0点
def getZeroPos(self):
postion = np.where(self.state == 0)
return postion
# 曼哈顿距离 f = g + h,g+1
def getFunctionValue(self):
cur_node = self.state.copy()
fin_node = self.answer.copy()
dist = 0
N = len(cur_node)
for i in range(N):
for j in range(N):
if cur_node[i][j] != fin_node[i][j]:
index = np.argwhere(fin_node == cur_node[i][j])
dist += 1
return dist + 1
def nextStep(self):
if not self.direction:
return []
subStates = []
boarder = len(self.state) - 1
# 获取0点位置;x是行,y是列
x, y = self.getZeroPos()
# 向左
if 'left' in self.direction and y > 0:
s = self.state.copy()
tmp = s[x, y - 1]
s[x, y - 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='right', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向上
if 'up' in self.direction and x > 0:
# it can move to upper place
s = self.state.copy()
tmp = s[x - 1, y]
s[x - 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='down', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向下
if 'down' in self.direction and x < boarder:
# it can move to down place
s = self.state.copy()
tmp = s[x + 1, y]
s[x + 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='up', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向右
if self.direction.count('right') and y < boarder:
# it can move to right place
s = self.state.copy()
tmp = s[x, y + 1]
s[x, y + 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='left', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
return subStates
# A* 迭代
def solve(self):
openTable.append(self)
while len(openTable) > 0:
openTable.sort(key=compareNum)
# 下一步的点移除open
n = openTable.pop(0)
# 加入close
closeTable.append(n)
# 确定下一步点
subStates = n.nextStep()
path = []
for subSta in subStates:
if (subSta.state == subSta.answer).all():
ansStates = subSta
while ansStates.parent and ansStates.parent != originState:
path.append(ansStates.parent)
ansStates = ansStates.parent
path.reverse()
return path
openTable.append(subSta)
else:
return None, None
def compareNum(state):
return state.f
if __name__ == '__main__':
# originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
# originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))
State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
# originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
# State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])
s1 = State(state=originState.state)
s_time = time.time()
# openList
openTable = []
# closeList
closeTable = []
path = s1.solve()
if path:
for node in path:
node.showInfo()
print(State.answer)
print("Total time is (ms):", (time.time() - s_time) * 1000)
print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
print("Total steps is %d" % len(path))
2、不在位数
import numpy as np
import time
class State:
def __init__(self, state, directionFlag=None, parent=None, f=0):
self.state = state
self.direction = ['up', 'down', 'right', 'left']
if directionFlag:
self.direction.remove(directionFlag)
self.parent = parent
self.f = f
def getDirection(self):
return self.direction
def setF(self, f):
self.f = f
return
# 打印结果
def showInfo(self):
for i in range(len(self.state)):
for j in range(len(self.state)):
print(self.state[i, j], end=' ')
print("\n")
print('->')
return
# 获取0点
def getZeroPos(self):
postion = np.where(self.state == 0)
return postion
# 曼哈顿距离 f = g + h,g+1
def getFunctionValue(self):
cur_node = self.state.copy()
fin_node = self.answer.copy()
dist = 0
N = len(cur_node)
for i in range(N):
for j in range(N):
if cur_node[i][j] != fin_node[i][j]:
index = np.argwhere(fin_node == cur_node[i][j])
dist += (abs(x - i) + abs(y - j))
return dist + 1
def nextStep(self):
if not self.direction:
return []
subStates = []
boarder = len(self.state) - 1
# 获取0点位置;x是行,y是列
x, y = self.getZeroPos()
# 向左
if 'left' in self.direction and y > 0:
s = self.state.copy()
tmp = s[x, y - 1]
s[x, y - 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='right', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向上
if 'up' in self.direction and x > 0:
# it can move to upper place
s = self.state.copy()
tmp = s[x - 1, y]
s[x - 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='down', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向下
if 'down' in self.direction and x < boarder:
# it can move to down place
s = self.state.copy()
tmp = s[x + 1, y]
s[x + 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='up', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向右
if self.direction.count('right') and y < boarder:
# it can move to right place
s = self.state.copy()
tmp = s[x, y + 1]
s[x, y + 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='left', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
return subStates
# A* 迭代
def solve(self):
openTable.append(self)
while len(openTable) > 0:
# 下一步的点移除open
n = openTable.pop(0)
# 加入close
closeTable.append(n)
# 确定下一步点
subStates = n.nextStep()
path = []
for subSta in subStates:
if (subSta.state == subSta.answer).all():
ansStates = subSta
while ansStates.parent and ansStates.parent != originState:
path.append(ansStates.parent)
ansStates = ansStates.parent
path.reverse()
return path
openTable.append(subSta)
else:
return None, None
def compareNum(state):
return state.f
if __name__ == '__main__':
# originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
# originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))
State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
# originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
# State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])
s1 = State(state=originState.state)
s_time = time.time()
# openList
openTable = []
# closeList
closeTable = []
path = s1.solve()
if path:
for node in path:
node.showInfo()
print(State.answer)
print("Total time is (ms):", (time.time() - s_time) * 1000)
print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
print("Total steps is %d" % len(path))
3、哈密尔顿距离
import numpy as np
import time
class State:
def __init__(self, state, directionFlag=None, parent=None, f=0):
self.state = state
self.direction = ['up', 'down', 'right', 'left']
if directionFlag:
self.direction.remove(directionFlag)
self.parent = parent
self.f = f
def getDirection(self):
return self.direction
def setF(self, f):
self.f = f
return
# 打印结果
def showInfo(self):
for i in range(len(self.state)):
for j in range(len(self.state)):
print(self.state[i, j], end=' ')
print("\n")
print('->')
return
# 获取0点
def getZeroPos(self):
postion = np.where(self.state == 0)
return postion
# 曼哈顿距离 f = g + h,g+1
def getFunctionValue(self):
cur_node = self.state.copy()
fin_node = self.answer.copy()
dist = 0
N = len(cur_node)
for i in range(N):
for j in range(N):
if cur_node[i][j] != fin_node[i][j]:
index = np.argwhere(fin_node == cur_node[i][j])
x = index[0][0] # 最终x距离
y = index[0][1] # 最终y距离
dist += (abs(x - i) + abs(y - j))
return dist + 1
def nextStep(self):
if not self.direction:
return []
subStates = []
boarder = len(self.state) - 1
# 获取0点位置;x是行,y是列
x, y = self.getZeroPos()
# 向左
if 'left' in self.direction and y > 0:
s = self.state.copy()
tmp = s[x, y - 1]
s[x, y - 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='right', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向上
if 'up' in self.direction and x > 0:
# it can move to upper place
s = self.state.copy()
tmp = s[x - 1, y]
s[x - 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='down', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向下
if 'down' in self.direction and x < boarder:
# it can move to down place
s = self.state.copy()
tmp = s[x + 1, y]
s[x + 1, y] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='up', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
# 向右
if self.direction.count('right') and y < boarder:
# it can move to right place
s = self.state.copy()
tmp = s[x, y + 1]
s[x, y + 1] = s[x, y]
s[x, y] = tmp
news = State(s, directionFlag='left', parent=self)
news.setF(news.getFunctionValue())
subStates.append(news)
return subStates
# A* 迭代
def solve(self):
openTable.append(self)
while len(openTable) > 0:
openTable.sort(key=compareNum)
# 下一步的点移除open
n = openTable.pop(0)
# 加入close
closeTable.append(n)
# 确定下一步点
subStates = n.nextStep()
path = []
for subSta in subStates:
if (subSta.state == subSta.answer).all():
ansStates = subSta
while ansStates.parent and ansStates.parent != originState:
path.append(ansStates.parent)
ansStates = ansStates.parent
path.reverse()
return path
openTable.append(subSta)
else:
return None, None
def compareNum(state):
return state.f
if __name__ == '__main__':
# originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
# originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))
State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
# originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
# State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])
s1 = State(state=originState.state)
s_time = time.time()
# openList
openTable = []
# closeList
closeTable = []
path = s1.solve()
if path:
for node in path:
node.showInfo()
print(State.answer)
print("Total time is (ms):", (time.time() - s_time) * 1000)
print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
print("Total steps is %d" % len(path))