说明
1、A*算法是解决静态路网中最短路径最有效的直接搜索方法。
2、A*算法是一种启发性算法,采用最佳优先搜索策略(Best-first),根据评估函数对每个搜索位置的评估结果,猜测最佳优先搜索位置。
A*算法大大降低了低质量的搜索路径,因此搜索效率高,比传统的路径规划算法更实时、更灵活。但A*算法找到了相对最好的路径,而不是绝对最短的路径,适用于大规模、高实时的问题。
实例
importheapq importcopy importre importdatetime BLOCK=[]#给定状态 GOAL=[]#目标状态 #4个方向 direction=[0,1],[0,-1],[1,0]0]] #OPEN表 OPEN=[] #节点的总数 SUM_NODE_NUM=0 #状态节点 classState(object): def__init__(self,gn=0,hn=0,state=None,hash_value=None,par=None): ''' 初始化 :paramgn:gn是从初始化到现在的距离 :paramhn:启发距离 :paramstate:存储节点的状态 :paramhash_value:哈希值,用于判重 :parampar:父节点指针 ''' self.gn=gn self.hn=hn self.fn=self.gn+self.hn self.child=[]#儿童节点 self.par=par#父节点 self.state=state#局面状态 self.hash_value=hash_value#哈希值 def__lt__(self,other):#用于堆叠比较,返回距离最小 returnself.fn<other.fn def__eq__(self,other):#相等的判断 returnself.hash_value==other.hash_value def__ne__(self,other):#不等的判断 returnnotself.__eq__(other) defmanhattan_dis(cur_node,end_node): ''' 计算曼哈顿的距离 :paramcur_state:当前状态 :return:曼哈顿到目的地的曼哈顿距离 ''' cur_state=cur_node.state end_state=end_node.state dist=0 N=len(cur_state) foriinrange(N): forjinrange(N): ifcur_state[i][j]==end_state[i][j]: continue num=cur_state[i][j] ifnum==0: x=N-1 y=N-1 else: x=num/N#理论横坐标 y=num-N*x-1#理论纵坐标 dist+=(abs(x-i)+abs(y-j)) returndist deftest_fn(cur_node,end_node): return0 defgenerate_child(cur_node,end_node,hash_set,open_table,dis_fn): ''' 产生子节点函数 :paramcur_node:当前节点 :paramend_node:最终状态节点 :paramhash_set:哈希表,用于判重 :paramopen_table:OPEN表 :paramdis_fn:距离函数 :return:None ''' ifcur_node==end_node: heapq.heappush(open_table,end_node) return num=len(cur_node.state) foriinrange(0,num): forjinrange(0,num): ifcur_node.state[i][j]!=0: continue fordindirection:#四个偏移方向 x=i+d[0] y=j+d[1] ifx<0orx>=numory<0ory>=num:#越界了 continue #记录扩展节点的数量 globalSUM_NODE_NUM SUM_NODE_NUM+=1 state=copy.deepcopy(cur_node.state)#复制父节点的状态 state[i][j],state[x][y]=state[x][y],state[i][j]#交换位置 h=hash(str(state))#哈希时,首先要转换成字符串 ifhinhash_set:#重复了 continue hash_set.add(h)#加入哈希表 gn=cur_node.gn+1#已经离函数走的距离函数 hn=dis_fn(cur_node,end_node)#启发的距离函数 node=State(gn,hn,state,h,cur_node)#新建节点 cur_node.child.append(node)#加入儿童队列 heapq.heappush(open_table,node)#加入到堆中 defprint_path(node): ''' 输出路径 :paramnode:最终的节点 :return:None ''' num=node.gn defshow_block(block): print("---------------") forbinblock: print(b) stack=[]#模拟栈 whilenode.parisnotNone: stack.append(node.state) node=node.par stack.append(node.state) whilelen(stack)!=0: t=stack.pop() show_block(t) returnnum defA_start(start,end,distance_fn,generate_child_fn,time_limit=10): ''' A*算法 :paramstart:起始状态 :paramend:终止状态 :paramdistance_fn:距离函数,可使用自定义 :paramgenerate_child_fn:产生儿童节点的函数 :paramtime_limit:默认时间限制为10秒 :return:None ''' root=State(0,0,start,hash(str(BLOCK)),None)#根节点 end_state=State(0,0,end,hash(str(GOAL)),None)#最后的节点 ifroot==end_state: print("start==end!") OPEN.append(root) heapq.heapify(OPEN) node_hash_set=set()#存储节点的哈希值 node_hash_set.add(root.hash_value) start_time=datetime.datetime.now() whilelen(OPEN)!=0: top=heapq.heappop(OPEN) iftop==end_state:#直接输出路径后结束 returnprint_path(top) #产生儿童节点,并在儿童节点添加OPEN表 generate_child_fn(cur_node=top,end_node=end_state,hash_set=node_hash_set, open_table=OPEN,dis_fn=distance_fn) cur_time=datetime.datetime.now() #超时处理 if(cur_time-start_time).seconds>time_limit: print("Timerunningout,break!") print("Numberofnodes:",SUM_NODE_NUM) return-1 print("Noroad!")#没有路径 return-1 defread_block(block,line,N): ''' 读取一行数据作为原始状态 :paramblock:原始状态 :paramline:一行数据 :paramN:数据的总数 :return:None ''' pattern=re.compile(r'\d+')#正则表达式提取数据 res=re.findall(pattern,line) t=0 tmp=[] foriinres: t+=1 tmp.append(int(i)) ift==N: t=0 block.append(tmp) tmp=[] if__name__='__main__': try: file=open("./infile.txt","r") exceptIOError: print("cannotopenfileinfile.txt!") exit(1) f=open("./infile.txt") NUMBER=int(f.readline()[-2]) n=1 foriinrange(NUMBER): l=[] forjinrange(NUMBER): l.append(n) n+=1 GOAL.append(l) GOAL[NUMBER-1][NUMBER-1]=0 forlineinf:#读取每行数据 OPEN=[]#别忘了在这里清空 BLOCK=[] read_block(BLOCK,line,NUMBER) SUM_NODE_NUM=0 start_t=datetime.datetime.now() #加5秒超时处理,可根据实际情况选择启发函数 length=A_start(BLOCK,GOAL,manhattan_dis,generate_child,time_limit=10) end_t=datetime.datetime.now() iflength!=-1: print("length=",length) print("time=",(end_t-start_t).total_seconds(),"s") print("Nodes=",SUM_NODE_NUM)
以上是python A*算法的介绍,希望对大家有所帮助。