A*求15码
2016-03-04 23:05
597 查看
解释一下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只记录零点的位置,这样倒序输出就得到零点移动路径,我们就知道这个数字是怎么移动的了.
[3]写了一个formed_print()函数用来将list按照矩阵的方式输出。
[4]开头一大串是测试用例.
import os import time from functools import reduce N = 16 #test case T = [4,7,8,3,6,13,15,2,1,11,5,12,0,14,10,9,0,-1] #obj = [4,7,8,3,6,13,15,2,1,11,5,12,14,10,0,9,0,-1] #T = [1,2,3,4,5,0,7,8,9,6,10,12,13,14,11,15,0,-1] #obj = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,-1] #obj = [4,7,8,3,6,0,15,2,1,13,5,12,14,11,10,9,0,-1]#1 #obj = [4,7,8,3,1,6,15,2,13,0,5,12,14,11,10,9] #2 #obj = [1,0,8,3,7,4,15,2,13,6,5,12,14,11,10,9]#3 #obj = [1,4,8,3,7,6,15,2,13,5,0,12,14,11,10,9]#10 #obj = [1,4,0,3,7,2,8,12,13,6,5,15,14,11,10,9]#20 #obj = [1,2,4,3,7,8,0,12,13,6,5,15,14,11,10,9] #25s #obj = [1,2,0,3,7,8,4,12,13,6,5,15,14,11,10,9]#29 #obj = [1,2,3,12,7,8,4,0,13,6,5,15,14,11,10,9] #31 #obj = [1,2,3,12,7,8,4,15,13,6,0,5,14,11,10,9]#33 #obj = [1,2,3,12,7,8,15,0,13,6,4,5,14,11,10,9] #34# #obj = [1,2,15,3,7,8,4,12,13,6,0,5,14,11,10,9] #39 #obj = [1,2,3,4,7,8,15,12,13,6,5,0,14,11,10,9] #45 #obj = [1,2,3,4,7,8,15,0,13,6,5,12,14,11,10,9] #47 #obj = [1,2,3,4,7,8,0,15,13,6,5,12,14,11,10,9]#48 #obj = [1,2,3,4,7,8,5,15,13,6,0,12,14,11,10,9]#49 #obj = [1,2,3,4,7,8,5,15,13,6,12,0,14,11,10,9] #50 obj = [1,2,3,4,5,13,6,15,14,7,11,10,0,9,8,12]#59 #obj = [1,2,3,4,5,13,6,15,14,11,0,10,9,7,8,12]#the final state def displacement(lhs,rhs):#compare the displacement 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 #*3 the larger the erro_dis is, the faster the search go on, with declines in the precision/accuracy 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):#return a list with swapped items temp = L[::] temp[i],temp[j] = temp[j],temp[i] return temp pos = curr_node.index(0)#find the position of 0 i,j = pos//4,pos%4#convert pos to grid coordinates 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 = []#the statelist openlist.append(T)#add the first node visit = {}#use visit to indicate being visited wait_visited ={} visit[get_state(T)] = 1; wait_visited[get_state(T)] = True#indicate the node that wait to be visited path[get_state(T)] = [-1,0]#four arguments means the (1)parent state,(2)pos of zero,(3)depth of node,(4)the evaluation of node while(len(openlist)!=0):#if the open list is empty,loop ends curr_node = openlist[0] state = get_state(curr_node) openlist.remove(curr_node) wait_visited[state] = False#meaning the node are visited if(curr_node[:-2] == obj):#if the obj is found,break the loop return path,curr_node,curr_node.index(0),state zero_pos,nextnodes = find_next_nodes(curr_node)#return all nodes near to 0 and pos of 0 for node in nextnodes: next_state = get_state(node) if(not(next_state in visit)):#the node is not visited and not waitting to be visited visit[next_state] = 1 wait_visited[next_state] = True path[next_state] = [state,zero_pos]#record the state path and the solution node[-2],node[-1] = curr_node[-2]+1,displacement(node,obj) openlist.append(node) sortedinsert(path,openlist,node)#insert the node in approriate position elif(wait_visited[next_state]== True):#meaning the node is waitting to be visited samenode = find_same_node(openlist,node) if(curr_node[-2]+1+displacement(node,obj)<samenode[-2]+samenode[-1]):#the new node is better node[-2],node[-1] = curr_node[-2]+1,displacement(node,obj) sortedinsert(path,openlist,node) #add the node which estimation is less 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)# display the steps 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)
相关文章推荐
- java学习之——安装与配置环境变量
- Android开发之蓝牙详解(三)
- 【HTML5】拖放
- 经典算法学习——非循环双向链表实现冒泡排序(带头结点尾结点)
- String[255]在高版本Delphi里还是被解释成Byte,总体长度256,使用StrPCopy可以给Array String拷贝字符串(内含许多实验测试)
- mysql命令
- mysql innodb_flush_log_at_trx_commit
- nyoj 115 城市平乱
- 一些Android经验
- struts2日常
- ng-repeat 嵌套 ng-switch 出错解决
- 学习linux决心书
- poj2532(BIT)
- AndroidStudio检测不到手机设备
- [SSH 3]以网上商城项目浅谈spring配置
- [SSH 3]以网上商城项目浅谈spring配置
- Python Tools for Visual Studio
- python 遍历目录下所有文件
- SWIG and Android
- Binarysearch 二分查找