解释一下A*算法,一种启发式搜索算法,用了一个估价函数f(n) = h(n)+g(n),其中g(n)是节点深度,h(n)是当前节点到目标节点的估计代价.特别要注意h(n),如果h(n)大于当前节点到目标节点的实际代价,那么可能就不能找到实际的最佳解决。这是因为该算法可能会将那些最优方案上的节点放在后面这样就会导致搜索到一些不那么优秀的方案.但是速度也越快.如果该h(n)小雨实际代价,那么就一定可以找到最优解,但是速度会慢.在N数码中,我们采取两个状态之间不相同数码的距离之和为h(n)(即某个数码要移动到目标位置的代价,abs(dx)+abs(dy))。g(n)是已知的,记录起来就可以了.
具体算法思路网上都有,就不说了,顺便测试了一下,确实估计代价越大速度越快,但是找出来的方案不是很优秀.
[0]除此之外,我们还需要建立路径的记录.这样可以让我们反向输出最佳反感.路径的记录用什么记录呢?我选择用python的dict(字典),因为这是动态数据结构,可以节省很多不必要的内存.假设你开一个数组(C语言),需要的大小是16!……就算是new出来的也很变态了。。。没有试过,不知道可以分配这么多不。。。
[1]另外这里采用hash查重,在python里面用dict记录访问状态就好了,把状态转换成一个字符串就可以作为key值了.为什么直接存储字符串呢?因为你用dict内存就不是我们要考虑的因素了,肯定够,所以直接转换成字符串简单点….如果你选择用康托展开来压缩状态成为一个整数的话,康托展开需要的时间更久,要一个双重循环。。。所以在内存够的情况下我们可以不压缩状态.
[2]另外我们的path只记录零点的位置,这样倒序输出就得到零点移动路径,我们就知道这个数字是怎么移动的了.
[4]开头一大串是测试用例.
import os
import time
from functools import reduce
N = 16
T = [4,7,8,3,6,13,15,2,1,11,5,12,0,14,10,9,0,-1]
obj = [1,2,3,4,5,13,6,15,14,7,11,10,0,9,8,12]
def displacement(lhs,rhs):
erro_dis = 0
for i in range(len(lhs)-2):
if(lhs[i]!=rhs[i]and rhs[i]!=0):
pos1,pos2 = lhs.index(rhs[i]),rhs.index(rhs[i])
x1,x2,y1,y2 = pos1//4,pos2//4,pos1%4,pos2%4
erro_dis = erro_dis + abs(x1-x2)+ abs(y1-y2)
return erro_dis
def formed_print(L):
n = 0;
for i in range(0,13,4):
t = L[i:i+4]
print(t[0],t[1],t[2],t[3])
print('\n')
def get_state(node):
sum = ''
for i in node[0:-2]:
sum += str(i)
return sum
def sortedinsert(path,openlist,newnode):
newnode_state = get_state(newnode)
for i,opennode in enumerate(openlist):
if(newnode[-2]+newnode[-1]<opennode[-2]+opennode[-1]):
openlist.insert(i,newnode)
return
openlist.append(newnode)
def find_next_nodes(curr_node):
def swap(L,i,j):
temp = L[::]
temp[i],temp[j] = temp[j],temp[i]
return temp
pos = curr_node.index(0)
i,j = pos//4,pos%4
nextnodes = []
if(i!=3):nextnodes.append(swap(curr_node,pos,pos+4))
if(i!=0):nextnodes.append(swap(curr_node,pos,pos-4))
if(j!=3):nextnodes.append(swap(curr_node,pos,pos+1))
if(j!=0):nextnodes.append(swap(curr_node,pos,pos-1))
return pos,nextnodes
def find_same_node(openlist,it):
for node in openlist:
if(node[:-2]==it[:-2]):
return node
def bfs():
path = {}
iscompleted = False
openlist = []
openlist.append(T)
visit = {}
wait_visited ={}
visit[get_state(T)] = 1;
wait_visited[get_state(T)] = True
path[get_state(T)] = [-1,0]
while(len(openlist)!=0):
curr_node = openlist[0]
state = get_state(curr_node)
openlist.remove(curr_node)
wait_visited[state] = False
if(curr_node[:-2] == obj):
return path,curr_node,curr_node.index(0),state
zero_pos,nextnodes = find_next_nodes(curr_node)
for node in nextnodes:
next_state = get_state(node)
if(not(next_state in visit)):
visit[next_state] = 1
wait_visited[next_state] = True
path[next_state] = [state,zero_pos]
node[-2],node[-1] = curr_node[-2]+1,displacement(node,obj)
openlist.append(node)
sortedinsert(path,openlist,node)
elif(wait_visited[next_state]== True):
samenode = find_same_node(openlist,node)
if(curr_node[-2]+1+displacement(node,obj)<samenode[-2]+samenode[-1]):
node[-2],node[-1] = curr_node[-2]+1,displacement(node,obj)
sortedinsert(path,openlist,node)
return False
def move(path,zero_pos,state):
zero_list = [zero_pos]
while(path[state][0]!=-1):
zero_list = [path[state][1]]+zero_list
state = path[state][0]
print('steps:',len(zero_list))
time.sleep(3)
for i in range(len(zero_list)-1):
os.system('cls')
formed_print(T)
time.sleep(0.1)
T[zero_list[i]],T[zero_list[i+1]] = T[zero_list[i+1]],T[zero_list[i]]
os.system('cls')
formed_print(T)
print(get_state(T))
path,node,zero_pos,state = bfs()
move(path,zero_pos,state)