获取 Python 中二维数组中单元格的最短路径
Get shortest path to a cell in a 2D array in Python
我有一个二维数组 arr
,其中每个单元格的值都是 1、2 或 3,例如 arr[0][0] = 3, arr[2][1] = 2, and arr[0][4] = 1
.
我想知道从给定的特定单元格(例如,arr[5][5]
到最近的值为 2 的单元格的最短路径,其中路径不应包含任何值为 1 的单元格。如何我可以这样做吗?
下面是 BFS 的脚本,但我怎样才能让它接受一个二维数组作为图形,并将起点作为数组中某个单元格的位置,然后从这个位置到最近的两个单元格避开带有 1 的单元格,因此它看起来像 bfs(2darray, starting location, 2)
?
def bfs(graph, start, end):
# Maintain a queue of paths
queue = []
# Push the first path into the queue
queue.append([start])
while queue:
# Get the first path from the queue
path = queue.pop(0)
# Get the last node from the path
node = path[-1]
# Path found
if node == end:
return path
# Enumerate all adjacent nodes, construct a new path and push it into the queue
for adjacent in graph.get(node, []):
new_path = list(path)
new_path.append(adjacent)
queue.append(new_path)
print bfs(graph, '1', '11')
如果列表不是太大,我发现最简单的解决方案是使用 NumPy 库的 where 函数来查找具有您要查找的值的单元格。因此,您需要将列表转换为 NumPy 数组。
下面的代码可能会被简化以使其更短、更高效,但这样会更清晰。顺便说一句,您可以计算两种距离:典型的欧几里德距离和 Manhattan.
如果在与原始单元格相同距离处有多个目标单元格,则min_coords对应于找到的第一个单元格(先按行,然后按列)。
import numpy as np
# The list needs to be transformed into an array in order to use the np.where method
# arr = np.random.randint(5, size=(6, 6))
arr = np.array([[0, 0, 0, 1, 1, 3],
[0, 0, 2, 1, 1, 0],
[0, 0, 1, 1, 1, 1],
[3, 0, 3, 1, 1, 1], ])
# Origin cell to make the search
x0, y0 = (1, 1)
targetValue = 3
# This is the keypoint of the problem: find the positions of the cells containing the searched value
positions = np.where(arr == targetValue)
x, y = positions
dx = abs(x0 - x) # Horizontal distance
dy = abs(y0 - y) # Vertical distance
# There are different criteria to compute distances
euclidean_distance = np.sqrt(dx ** 2 + dy ** 2)
manhattan_distance = abs(dx + dy)
my_distance = euclidean_distance # Criterion choice
min_dist = min(my_distance)
print(min_dist)
min_pos = np.argmin(my_distance) # This method will only return the first occurrence (!)
min_coords = x[min_pos], y[min_pos]
print(min_coords)
您可以为此使用简单的 breadth first search。基本上,网格中的每个单元格对应于图中的一个节点,相邻单元格之间有边。从起始位置开始,不断扩展可通过的单元格,直到找到目标单元格。
def bfs(grid, start):
queue = collections.deque([[start]])
seen = set([start])
while queue:
path = queue.popleft()
x, y = path[-1]
if grid[y][x] == goal:
return path
for x2, y2 in ((x+1,y), (x-1,y), (x,y+1), (x,y-1)):
if 0 <= x2 < width and 0 <= y2 < height and grid[y2][x2] != wall and (x2, y2) not in seen:
queue.append(path + [(x2, y2)])
seen.add((x2, y2))
网格设置和结果:(请注意,我使用符号而不是数字,原因很简单,这样更容易直观地解析网格并验证解决方案。)
wall, clear, goal = "#", ".", "*"
width, height = 10, 5
grid = ["..........",
"..*#...##.",
"..##...#*.",
".....###..",
"......*..."]
path = bfs(grid, (5, 2))
# [(5, 2), (4, 2), (4, 3), (4, 4), (5, 4), (6, 4)]
我有一个二维数组 arr
,其中每个单元格的值都是 1、2 或 3,例如 arr[0][0] = 3, arr[2][1] = 2, and arr[0][4] = 1
.
我想知道从给定的特定单元格(例如,arr[5][5]
到最近的值为 2 的单元格的最短路径,其中路径不应包含任何值为 1 的单元格。如何我可以这样做吗?
下面是 BFS 的脚本,但我怎样才能让它接受一个二维数组作为图形,并将起点作为数组中某个单元格的位置,然后从这个位置到最近的两个单元格避开带有 1 的单元格,因此它看起来像 bfs(2darray, starting location, 2)
?
def bfs(graph, start, end):
# Maintain a queue of paths
queue = []
# Push the first path into the queue
queue.append([start])
while queue:
# Get the first path from the queue
path = queue.pop(0)
# Get the last node from the path
node = path[-1]
# Path found
if node == end:
return path
# Enumerate all adjacent nodes, construct a new path and push it into the queue
for adjacent in graph.get(node, []):
new_path = list(path)
new_path.append(adjacent)
queue.append(new_path)
print bfs(graph, '1', '11')
如果列表不是太大,我发现最简单的解决方案是使用 NumPy 库的 where 函数来查找具有您要查找的值的单元格。因此,您需要将列表转换为 NumPy 数组。
下面的代码可能会被简化以使其更短、更高效,但这样会更清晰。顺便说一句,您可以计算两种距离:典型的欧几里德距离和 Manhattan.
如果在与原始单元格相同距离处有多个目标单元格,则min_coords对应于找到的第一个单元格(先按行,然后按列)。
import numpy as np
# The list needs to be transformed into an array in order to use the np.where method
# arr = np.random.randint(5, size=(6, 6))
arr = np.array([[0, 0, 0, 1, 1, 3],
[0, 0, 2, 1, 1, 0],
[0, 0, 1, 1, 1, 1],
[3, 0, 3, 1, 1, 1], ])
# Origin cell to make the search
x0, y0 = (1, 1)
targetValue = 3
# This is the keypoint of the problem: find the positions of the cells containing the searched value
positions = np.where(arr == targetValue)
x, y = positions
dx = abs(x0 - x) # Horizontal distance
dy = abs(y0 - y) # Vertical distance
# There are different criteria to compute distances
euclidean_distance = np.sqrt(dx ** 2 + dy ** 2)
manhattan_distance = abs(dx + dy)
my_distance = euclidean_distance # Criterion choice
min_dist = min(my_distance)
print(min_dist)
min_pos = np.argmin(my_distance) # This method will only return the first occurrence (!)
min_coords = x[min_pos], y[min_pos]
print(min_coords)
您可以为此使用简单的 breadth first search。基本上,网格中的每个单元格对应于图中的一个节点,相邻单元格之间有边。从起始位置开始,不断扩展可通过的单元格,直到找到目标单元格。
def bfs(grid, start):
queue = collections.deque([[start]])
seen = set([start])
while queue:
path = queue.popleft()
x, y = path[-1]
if grid[y][x] == goal:
return path
for x2, y2 in ((x+1,y), (x-1,y), (x,y+1), (x,y-1)):
if 0 <= x2 < width and 0 <= y2 < height and grid[y2][x2] != wall and (x2, y2) not in seen:
queue.append(path + [(x2, y2)])
seen.add((x2, y2))
网格设置和结果:(请注意,我使用符号而不是数字,原因很简单,这样更容易直观地解析网格并验证解决方案。)
wall, clear, goal = "#", ".", "*"
width, height = 10, 5
grid = ["..........",
"..*#...##.",
"..##...#*.",
".....###..",
"......*..."]
path = bfs(grid, (5, 2))
# [(5, 2), (4, 2), (4, 3), (4, 4), (5, 4), (6, 4)]