如何轻松了解迷宫是否有从开始到目标的道路?

时间:2009-11-12 08:44:52

标签: 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 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

can_visit?方法检查节点是否在迷宫内,节点是否被访问,节点是否被阻塞。

5 个答案:

答案 0 :(得分:6)

最糟糕的答案可能。

1)走到前面,直到你无法移动

2)左转

3)冲洗并重复。

如果你做到了,那就结束了。

更好的解决方案。

遍历迷宫,保留2个开放和封闭节点列表。使用着名的A-Star算法 选择评估下一个节点并丢弃作为死胡同的节点。如果打开列表中的节点用完,则没有退出。

答案 1 :(得分:3)

这是一个简单的算法,应该快得多:

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

  • 找到迷宫中死角的所有地方(它们有三面墙)。移回下一个交汇点并从搜索树中取出此路径。

以这种方式移除所有死角之后,应该留下一条路径(如果有多种方法可以达到目标,则为几条路径。)

答案 2 :(得分:2)

我不会在那里使用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

是的,这是愚蠢的,是的,它是面包和所有的。

这是A *实施

def dist(x,y):
  return (abs(x[0]-y[0]) + abs(x[1]-y[1]))^2

def heuristic(x,y):
  return (x[0]-y[0])^2 + (x[1]-y[1])^2

def find(open,f):
  result = None
  min = None
  for x in open:
    tmp = f[x[0]][x[1]]
    if min == None or tmp < min:
      min = tmp
      result = x
  return result

def neighbors(x,m,n):
  def add(result,y,m,n):
    if x < m and y < n: result.append(y)
  result = []
  add(result, (x[0]-1,x[1]), m, n)
  add(result, (x[0],x[1]-1), m, n)
  add(result, (x[0]+1,x[1]), m, n)
  add(result, (x[0],x[1]+1), m, n)
  return result

def canBeTraversedAStar(maze):
  m = len(maze)
  n = len(maze[0])

  goal = (m-1,n-1)

  closed = set([])
  open = set([(0,0),])

  g = [ [ 0 for y in range(0,n) ] for x in range(0,m) ]
  h = [ [ heuristic((x,y),goal) for y in range(0,n) ] for x in range(0,m) ]
  f = [ [ h[x][y] for y in range(0,n) ] for x in range(0,m) ]

  while len(open) != 0:
    x = find(open,f)
    if x == (m-1,n-1):
      return True
    open.remove(x)
    closed.add(x)

    for y in neighbors(x,m,n):
      if y in closed: continue

      if y not in open:
        open.add(y)

        g[y[0]][y[1]] = g[x[0]][x[1]] + dist(x,y)
        h[y[0]][y[1]] = heuristic(y,goal)
        f[y[0]][y[1]] = g[y[0]][y[1]] + h[y[0]][y[1]]

  return True

这是我的(简单)基准代码:

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

显而易见的是:要让A *顺利运行需要进行大量优化,我没有费心去追求......

我会说:

  1. 不优化
  2. (仅限专家)不优化
  3. 当你说得太多时,你在谈论多长时间?真的是一个100x100网格很容易被蛮力解析它是一个笑话:/

答案 3 :(得分:0)

我会用AStar实现解决这个问题。如果你想要更高的速度,你可以优化只从结点生成节点而不是每个瓦片/方块/步骤。

答案 4 :(得分:0)

您可以使用的方法无需访问迷宫中的所有节点,如下所示:

  • 创建一个整数[] [],每个迷宫有一个值“room”
  • 创建一个队列,添加[startpoint,count = 1,delta = 1]和[goal,count = -1,delta = -1]
  • 开始为路线着色:
    • 从队列的头部弹出一个对象,将计数放在迷宫点。
    • 检查所有可到达的房间是否有与房间三角形相反的标志的计数,如果您发现一个迷宫已经解决:双向运行并连接在房间数量上下最大步骤的路线。
    • 否则将所有没有计数的可到达房间添加到队列的尾部,并将delta添加到房间数。
    • 如果队列为空,则无法通过迷宫。

这不仅可以确定是否有路径,还可以显示迷宫中可能的最短路径。

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