Python 理解单目标迷宫的A*启发法
我有一个迷宫,如下所示:Python 理解单目标迷宫的A*启发法,python,artificial-intelligence,path-finding,a-star,heuristics,Python,Artificial Intelligence,Path Finding,A Star,Heuristics,我有一个迷宫,如下所示: |||||||||||||||||||||||||||||||||||| | P| | ||||||||||||||||||||||| |||||||| | | || | | ||||||| || | | || | | | | |||| ||||||||| || ||||| | || | | | | || || | | || | | | | |
||||||||||||||||||||||||||||||||||||
| P|
| ||||||||||||||||||||||| |||||||| |
| || | | ||||||| || |
| || | | | | |||| ||||||||| || |||||
| || | | | | || || |
| || | | | | | |||| ||| |||||| |
| | | | | | || |||||||| |
| || | | |||||||| || || |||||
| || | || ||||||||| || |
| |||||| ||||||| || |||||| |
|||||| | |||| || | |
| |||||| ||||| | || || |||||
| |||||| | ||||| || |
| |||||| ||||||||||| || || |
|||||||||| |||||| |
|+ |||||||||||||||| |
||||||||||||||||||||||||||||||||||||
目标是让p
找到+
,子目标为
- 到
的路径成本最低(1跳=成本+1)+
- 搜索的单元数(展开的节点)最小化
#Greedy Best First -- Manhattan Distance
self.heuristic = abs(goalNodeXY[1] - self.xy[1]) + abs(goalNodeXY[0] - self.xy[0])
#A* -- Manhattan Distance + Path Cost from 'startNode' to 'currentNode'
return abs(goalNodeXY[1] - self.xy[1]) + abs(goalNodeXY[0] - self.xy[0]) + self.costFromStart
在这两种算法中,我都使用了一个heapq
,根据启发式值进行优先级排序。以下两种情况的主搜索循环相同:
theFrontier = []
heapq.heappush(theFrontier, (stateNode.heuristic, stateNode)) #populate frontier with 'start copy' as only available Node
#while !goal and frontier !empty
while not GOAL_STATE and theFrontier:
stateNode = heapq.heappop(theFrontier)[1] #heappop returns tuple of (weighted-idx, data)
CHECKED_NODES.append(stateNode.xy)
while stateNode.moves and not GOAL_STATE:
EXPANDED_NODES += 1
moveDirection = heapq.heappop(stateNode.moves)[1]
nextNode = Node()
nextNode.setParent(stateNode)
#this makes a call to setHeuristic
nextNode.setLocation((stateNode.xy[0] + moveDirection[0], stateNode.xy[1] + moveDirection[1]))
if nextNode.xy not in CHECKED_NODES and not isInFrontier(nextNode):
if nextNode.checkGoal(): break
nextNode.populateMoves()
heapq.heappush(theFrontier, (nextNode.heuristic,nextNode))
现在我们来讨论这个问题。虽然A*找到了最佳路径,但这样做的成本相当高。为了找到cost:68
的最佳路径,它扩展(导航和搜索)452个节点来完成此操作。
而贪婪的最佳实现只在160次扩展中找到了次优路径(成本:74)
我真的很想知道我错在哪里。我意识到贪婪的最佳优先算法可以自然地表现出这样的行为,但是节点扩展中的差距太大了,我觉得这里一定出了问题。。任何帮助都将不胜感激。如果我在上面粘贴的内容在某种程度上不清楚,我很乐意添加详细信息。A*search试图找到问题的最佳解决方案,而贪婪的best first则试图找到任何解决方案。A*有一个非常非常困难的任务,它必须投入大量的工作来探索可能是最好的每一条路径,而贪婪的最佳优先算法只是直接寻找最接近目标的选项。A*提供了问题的最佳答案,贪婪的最佳优先搜索提供了任何解决方案 预计A*必须做更多的工作 如果您希望a*的变化不再是最优的,但返回解的速度要快得多,您可以查看加权a*。它只包括给启发式设置权重(权重>1)。在实践中,它会给您带来巨大的性能提升 例如,您可以尝试以下方法:
return 2*(abs(goalNodeXY[1] - self.xy[1]) + abs(goalNodeXY[0] - self.xy[0])) + self.costFromStart
因为这个问题还没有解决,即使OP提出的错误可以解决,我觉得我需要问这个问题,也许可以回答什么是错误的,为什么Fezvez的答案可以解决这个问题:你是否用*算法检查了所有节点的启发式值,并注意到了一些奇怪的事情?他们不都是平等的吗?因为即使您的启发式对于最佳优先算法是正确的,它也不能直接适用于您的a*算法。我用java做了一个类似的项目,我遇到了这个问题,这就是为什么我要问这个问题。例如,假设您有以下兴趣点:
- 开始(P)-(0,0)
- 结束(+)-(20,20)
- P1-(2,2)->(你的启发式)+(路径成本)=((20-2)+(20-2))+((2-0)+(2-0))=40
- P2-(4,3)->(你的启发式)+(路径成本)=(20-4)+(20-3))+((4-0)+(3-0))=40
- 开始(P)-(0,0)
- 结束(+)-(20,20)
- P1-(2,2)->2*(你的启发式)+(路径成本)=2*((20-2)+(20-2))+((2-0)+(2-0))=76
- P2-(4,3)->2*(你的启发式)+(路径成本)=2*((20-4)+(20-3))+((4-0)+(3-0))=73
CHECKED\u NODES.append(nextNode.xy)
——这似乎将我对这两种算法的扩展减少了一半。。。