简体   繁体   English

如何在 X*Y 网格中找到最短路径

[英]How to find shortest path in X*Y grid

I have a grid N*M in Python.我在 Python 中有一个 N*M 网格。

where在哪里

"X" represents the border, “X”代表边界,

"1" represents current position, “1”代表当前位置,

"2" represents finish, and “2”代表完成,并且

"3" represents forbidden locations. “3”代表禁止位置。

The last thing is that (imagine you're a car) you can go only straight or right.最后一件事是(想象你是一辆车)你只能直行或右行。

Example 3x3 except borders:示例 3x3 除边框外:

[X,X,X,X,X]
[X,2,1,0,X]
[X,0,3,0,X]
[X,0,0,0,X]
[X,X,X,X,X]

Another example:另一个例子:

[X,X,X,X,X]
[X,2,0,0,X]
[X,3,3,1,X]
[X,X,X,X,X]

Or another:或其他:

[X,X,X,X,X,X,X]
[X,0,2,0,0,0,X]
[X,0,3,0,3,0,X]
[X,0,0,0,0,0,X]
[X,0,3,0,3,0,X]
[X,0,3,1,3,0,X]
[X,X,X,X,X,X,X]

Do you have any suggestion for concrete script that will find the fastest way?您对可以找到最快方法的具体脚本有什么建议吗?

And if there's not, print("No solution")?如果没有,打印(“无解”)?

Thank you very much!非常感谢!

To help you understand these situations:为了帮助您了解这些情况:

pictures of examples 1 and 2示例 1 和 2 的图片

This was a fun one.这是一个有趣的。 A brute force approach calculates all possible paths through the system, and finally finds minimum path length of those ending in 2. Note that init just returns a valid matrix with which to work.蛮力方法计算通过系统的所有可能路径,并最终找到以 2 结尾的路径的最小路径长度。注意 init 只返回一个有效的矩阵。 If no solution is found for the matrix, None is returned by solve function.如果没有找到矩阵的解,solve 函数返回 None 。

BLOCK=3
FINAL=2
TERMINATE=None
INITIAL=1
PATH=0

def init(n,m):
  # returns array with essential components, but not necessarily with solution
  import numpy
  import random
  while True:
    try:
      a=numpy.zeros((n,m),dtype=int)
      for i in range(n):
        for j in range(m):
          t=INITIAL
          # initialize to anything but INITIAL
          while t==INITIAL: t=numpy.random.randint(PATH,BLOCK)
          a[i,j]=t
      c=random.choice(list(zip(*(a==PATH).nonzero())))
      a[c]=INITIAL
      finals=list(zip(*(a==FINAL).nonzero()))
      c=random.choice(finals)
      for i in finals:
        if i!=c: a[i]=BLOCK
      break
    except:
      continue
  return a

def possible_moves(a,pos):
  n,m=a.shape
  test_moves=[(0,1),(1,0),(-1,0),(0,-1)]
  #print('from pos={}'.format(pos))
  x,y=pos[0:2]
  valid_moves=[]
  for t in test_moves:
    new=(t[0]+x,t[1]+y)
    if t[0]+x>-1 and \
       t[0]+x<n and \
       t[1]+y>-1 and \
       t[1]+y<m:
      if a[new] not in [BLOCK]:
        valid_moves.append((t[0]+x,t[1]+y))
  return valid_moves

def allpaths(a,paths):
  for path in paths:
    if path[-1] in [TERMINATE,FINAL]: continue
    pos=path[-1]
    moves=possible_moves(a,pos)
    if not moves:
      path.append(TERMINATE) # if no moves left, path is terminated
      continue
    base=path.copy()
    for im,move in enumerate(moves):
      b=a.copy()
      # set previous position to BLOCK so can't move into previous positions
      b[pos]=BLOCK
      if im==0:
        if a[move]==FINAL: path.append(FINAL) # if position to move to is FINAL, indicate
        else: path.append(move)
      else:
        if a[move]==FINAL: paths.append(base+[FINAL])
        else: paths.append(base+[move])
    paths=allpaths(b,paths)
  return paths

def solve(a):
  ipos=list(zip(*(a==INITIAL).nonzero()))
  paths=[ipos]
  paths=allpaths(a,paths)
  M=a.shape[0]*a.shape[1]
  minlen=M
  for path in paths:
    if path[-1] in [FINAL]:
      minlen=min(minlen,len(path)-1)
  if minlen==M: return None
  else: return minlen

n,m=5,6
a=init(n,m)
print(n,m)
print(a)

minlen=solve(a)
print(minlen)

To capture "right," you could simply track previous position through to the possible_moves function, and ensure you are returning only "straight" and "right" directions ("backward" is already guarded against as it's encoded).要捕获“右”,您可以简单地通过 possible_moves 函数跟踪先前的位置,并确保您只返回“直”和“右”方向(“向后”在编码时已经受到保护)。

You can use this code, which based on Grap theory:您可以使用此代码,它基于 Grap 理论:

grid = [
['X','X','X','X','X','X','X'],
['X',2,0,0,0,0,'X'],
['X',0,3,0,3,0,'X'],
['X',0,0,0,0,0,'X'],
['X',0,3,0,3,0,'X'],
['X',0,3,1,3,0,'X'],
['X','X','X','X','X','X','X']
]


INF=1000000

def is_valid(grid:list):
    ends = 0
    starts = 0
    for line in grid:
        for el in line:
            if el==2:
                ends+=1
            if el==1:
                starts+=1
    return False if ends!=1 or starts!=1 else True

def redef_grid(grid:list):
    ''' Deleting from grid all 'X' '''
    g=grid.copy()
    if 'X' in g[0]: del g[0]
    if 'X' in g[-1]: del g[-1]
    for line in g:
        while 'X' in line:
            line.remove('X')
    return g

def uni_index(grid:list, pos:tuple):
    return len(grid[0])*pos[0]+pos[1]

def real_index(grid:list, index:int):
    row =index//len(grid[0])
    col=index-row*len(grid[0])
    return (row, col)

def get_neibs(grid:list, index:int):
    def get_vertical(grid:list, index:int):
        return [index+k for k in [len(grid[0]), -len(grid[0])] if index+k>=0 and index+k<uni_index(grid, (len(grid)-1, len(grid[0])-1))]
    def get_horizontal(grid:list, index:int):
        return [index+k for k in [1, -1] if index+k>=(index//len(grid[0]))*(len(grid[0])) and index+k<=uni_index(grid, (index//len(grid[0]), len(grid[0])-1))]
    return get_vertical(grid, index)+get_horizontal(grid, index)

def get_matrix(grid:list):
    last_el = uni_index(grid, (len(grid)-1, len(grid[0])-1))
    elements=len(grid[0])*len(grid)
    matrix=[[INF for _ in range(elements)] for _ in range(elements)]
    for index in range(last_el):
        neibs=get_neibs(grid, index)
        neibs=[neib for neib in neibs if grid[real_index(grid, neib)[0]][real_index(grid, neib)[1]]!=3]
        for neib in neibs:
            matrix[index][neib]=1
    return matrix

def get_start(grid:list):
    for i in range(len(grid)):
        try:
            return (i, grid[i].index(1))
        except ValueError:
            pass

def get_end(grid:list):
    for i in range(len(grid)):
        try:
            return (i, grid[i].index(2))
        except ValueError:
            pass

def Dijkstra(N, S, matrix):
    valid = [True]*N
    weight = [1000000]*N
    weight[S] = 0
    for i in range(N):
        min_weight = 1000001
        ID_min_weight = -1
        for i in range(N):
            if valid[i] and weight[i] < min_weight:
                min_weight = weight[i]
                ID_min_weight = i
        for i in range(N):
            if weight[ID_min_weight] + matrix[ID_min_weight][i] < weight[i]:
                weight[i] = weight[ID_min_weight] + matrix[ID_min_weight][i]
        valid[ID_min_weight] = False
    return weight

grid=redef_grid(grid)
if is_valid(grid):
    matrix=get_matrix(grid)
    paths = Dijkstra(len(grid)*len(grid[0]), uni_index(grid, get_start(grid)), matrix)
    shortest_path = paths[uni_index(grid, get_end(grid))]
    if shortest_path==INF: shortest_path='No solution'
    print(shortest_path)
else: print('Invalid grid')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM