Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何轻松知道迷宫是否有一条从起点到终点的道路?_Algorithm - Fatal编程技术网

Algorithm 如何轻松知道迷宫是否有一条从起点到终点的道路?

Algorithm 如何轻松知道迷宫是否有一条从起点到终点的道路?,algorithm,Algorithm,我使用0,1数组实现了一个迷宫。迷宫中的入口和目标是固定的。入口始终为迷宫的0,0点。目标始终是迷宫的m-1、n-1点。我现在使用广度优先搜索算法,但速度不够快。特别适用于大型迷宫(100*100左右)。有人能帮我做一下这个算法吗 以下是我的解决方案: queue = [] position = start_node mark_tried(position) queue << position while(!queue.empty?) p = queue.shift #pop

我使用0,1数组实现了一个迷宫。迷宫中的入口和目标是固定的。入口始终为迷宫的0,0点。目标始终是迷宫的m-1、n-1点。我现在使用广度优先搜索算法,但速度不够快。特别适用于大型迷宫(100*100左右)。有人能帮我做一下这个算法吗

以下是我的解决方案:

queue = []
position = start_node
mark_tried(position)
queue << position
while(!queue.empty?)
  p = queue.shift  #pop the first element
  return true if maze.goal?(p)
  left = p.left
  visit(queue,left) if can_visit?(maze,left)
  right = p.right
  visit(queue,right) if can_visit?(maze,right)
  up = p.up
  visit(queue,up) if can_visit?(maze,up)
  down = p.down
  visit(queue,down) if can_visit?(maze,down)
end
return false
queue=[]
位置=开始节点
mark_(职位)

队列可能是最差的答案

1) 向前走,直到你不能动为止

2) 左转

3) 冲洗并重复

如果你成功了,就有一个结局

更好的解决方案

在迷宫中穿行,为打开和关闭的节点保留两个列表。使用著名的算法
选择“计算下一个节点”和“放弃死角节点”。如果打开的列表中的节点已用完,则不会有出口。

以下是一个简单的算法,速度应该快得多:

  • 从起点/终点移动到第一个交叉点。您可以忽略该连接点和开始/目标之间的任何内容

  • 确定迷宫中所有死角的位置(它们有三面墙)。返回到下一个交叉点,并将此路径从搜索树中删除


以这种方式消除所有死胡同后,应该只剩下一条路(或者如果有几种方法可以达到目标,则有几种方法)。

我会用一个实现来解决这个问题。如果您想要更高的速度,您可以优化为仅从交叉点生成节点,而不是从每个平铺/正方形/步骤生成节点。

一种不需要访问迷宫中所有节点的方法如下:

  • 创建一个整数[],每个迷宫“房间”有一个值
  • 创建一个队列,添加[startpoint,count=1,delta=1]和[goal,count=-1,delta=-1]
  • 通过以下方式开始为路线着色:
    • 从队列头弹出一个对象,将计数放在迷宫点
    • 检查所有可到达的房间是否有与房间三角形相反的计数标志,如果发现其中一个,则迷宫已解决:双向运行,并连接房间计数上下最大台阶的路线
    • 否则,将所有无计数的可到达房间添加到队列尾部,房间计数中添加增量
    • 如果队列为空,则无法通过迷宫
这不仅可以确定是否存在路径,还可以显示通过迷宫的最短路径


你不需要回溯,所以它是O(迷宫房间的数量)

我不会在那里使用AStar算法,除非我真的需要,因为这可以通过一些简单的“着色”来完成

# maze is a m x n array
def canBeTraversed(maze):
  m = len(maze)
  n = len(maze[0])

  colored = [ [ False for i in range(0,n) ] for j in range(0,m) ]

  open = [(0,0),]

  while len(open) != 0:
    (x,y) = open.pop()
    if x == m-1 and y == n-1:
      return True
    elif x < m and y < n and maze[x][y] != 0 not colored[x][y]:
      colored[x][y] = True
      open.extend([(x-1,y), (x,y-1), (x+1,y), (x,y+1)])

  return False
哪些产出:

# For canBeTraversed
100 x 100 : 0:00:00.002650 average on 100 runs
1000 x 1000 : 0:00:00.198440 average on 100 runs

# For canBeTraversedAStar
100 x 100 : 0:00:00.016100 average on 100 runs
1000 x 1000 : 0:00:01.679220 average on 100 runs
这里显而易见的一点是:要使A*顺利运行,需要进行大量优化,我没有费心去追求

我想说:

  • 不要优化
  • (仅限专家)暂时不要优化

  • 当你说得太多的时候,你在说多少时间?实际上,100x100网格非常容易用蛮力解析,这是一个笑话://

    使用这种方法时要小心。由于闭环,可能存在死胡同。这样一个循环只有两堵墙,会导致你永远循环。保留一个正在运行的节点列表。如果你再次遇到同一个节点,你的循环。对于A-Star算法,我已经阅读了wiki页面,我认为我不需要节点的分数,但是没有分数,这只是简单的呼吸优先搜索,没有比我的解决方案更好的了。高是对的——在一个随机迷宫中,你不能可靠地得到A*——线性接近出口并不意味着什么。@尼克:事实上,你可以,因为启发式只需要有一个属性,它决不会低估从一点到目标的距离。因此,你可以使用直线距离。@Peter:你的意思不是高估了吗?低估在A*(例如使用欧几里得距离)中似乎很常见@Matthieu:是的。应该说“永远不要高估”。
    def tryIt(func,size, runs):
      maze = [ [ 1 for i in range(0,size) ] for j in range(0,size) ]
      begin = datetime.datetime.now()
      for i in range(0,runs): func(maze)
      end = datetime.datetime.now()
    
      print size, 'x', size, ':', (end - begin) / runs, 'average on', runs, 'runs'
    
    tryIt(canBeTraversed,100,100)
    tryIt(canBeTraversed,1000,100)
    
    tryIt(canBeTraversedAStar,100,100)
    tryIt(canBeTraversedAStar,1000,100)
    
    # For canBeTraversed
    100 x 100 : 0:00:00.002650 average on 100 runs
    1000 x 1000 : 0:00:00.198440 average on 100 runs
    
    # For canBeTraversedAStar
    100 x 100 : 0:00:00.016100 average on 100 runs
    1000 x 1000 : 0:00:01.679220 average on 100 runs