Python breadth-first search matrix print path

只愿长相守 提交于 2019-12-20 03:52:31

问题


I have this line of code that tests wether or not there is a path to be found in a labyrinth represented by a matrix. How do I print the path at the end after I've determined wether or not there is a path. I've tried doing a stack but I'm not sure how to proceed.

from queue import Queue
maze=open(input())
matrix=maze.readlines()
matrix=[i.strip() for i in matrix]
matrix=[i.split() for i in matrix]
numrows, numcols = len(matrix), len(matrix[0])
q=Queue()
row=0
col=0
q.put((row,col))
while not q.empty():
    row, col = q.get()
    if col+1 < numcols and matrix[row][col+1] == "0":
         q.put((row, col+1))
         matrix[row][col+1] = "2"
    if row+1 < numrows and matrix[row+1][col] == "0":
         q.put((row+1, col))
         matrix[row+1][col] = "3"
    if 0 <= col-1 and matrix[row][col-1] == "0":
         q.put((row, col-1))
         matrix[row][col-1] = "4"
    if 0 <= row-1 and matrix[row-1][col] == "0":
         q.put((row-1, col))
         matrix[row-1][col] = "5" 
row,col=numrows-1,numcols-1
var=matrix[row][col]
if var=="0":
    print ("There is no path.")
else:
    print ("There is a path.")

Here is a sample matrix:

0 0 0 0 1 0 0 0
0 1 1 0 1 0 1 0
0 1 0 0 1 0 1 0
0 0 0 1 0 0 1 0
0 1 0 1 0 1 1 0
0 0 1 1 0 1 0 0
1 0 0 0 0 1 1 0
0 0 1 1 1 1 0 0

回答1:


Because you are using BFS to find the path, the final approach cannot be the shortest path from the start point to the finish point, and actually, you can only get the result that which point is connected to the start point.

So, to get an exact path, you may use DFS to find a path and use a stack to save the points visited or use Dijkstra to find the shortest path from the start point to the finish point.

Here is a simple DFS function which uses recursion and the path is represented in character 2

suc = 0

def dfs(row, col):
    global suc
    if suc == 1:
        return
    matrix[row][col] = "2"

    if (row, col) == (numrows - 1, numcols - 1):
        print("Success")
        suc = 1

    if col + 1 < numcols and matrix[row][col + 1] == "0":
        dfs(row, col + 1)

    if row + 1 < numrows and matrix[row + 1][col] == "0":
        dfs(row + 1, col)

    if 0 <= col - 1 and matrix[row][col - 1] == "0":
        dfs(row, col - 1)

    if 0 <= row - 1 and matrix[row - 1][col] == "0":
        dfs(row - 1, col)


maze = open(input())
matrix = maze.readlines()
matrix = [i.strip() for i in matrix]
matrix = [i.split() for i in matrix]
numrows, numcols = len(matrix), len(matrix[0])

dfs(0, 0)

var = matrix[numrows - 1][numcols - 1]

for m in matrix:
    print(m)

if var == "0":
    print("There is no path.")
else:
    print("There is a path.")



回答2:


Here's a fairly simple way to find the path, by tracing it backwards from the exit. You can reverse this by saving the moves to a stack.

To make it easier to see, I've changed your code slightly to put N, S, E, W in the matrix (for North, South, East, West). To decode those direction letters to (row, column) steps I use a dictionary.

from queue import Queue

maze='''\
0 0 0 0 1 0 0 0
0 1 1 0 1 0 1 0
0 1 0 0 1 0 1 0
0 0 0 1 0 0 1 0
0 1 0 1 0 1 1 0
0 0 1 1 0 1 0 0
1 0 0 0 0 1 1 0
0 0 1 1 1 1 0 0
'''

def show(matrix):
    for line in matrix:
        print(*line)
    print()

matrix=maze.splitlines()
matrix=[i.strip() for i in matrix]
matrix=[i.split() for i in matrix]
numrows, numcols = len(matrix), len(matrix[0])

show(matrix)

q=Queue()
row=0
col=0
q.put((row,col))
while not q.empty():
    row, col = q.get()
    if col+1 < numcols and matrix[row][col+1] == "0":
         q.put((row, col+1))
         matrix[row][col+1] = "W"
    if row+1 < numrows and matrix[row+1][col] == "0":
         q.put((row+1, col))
         matrix[row+1][col] = "N"
    if 0 <= col-1 and matrix[row][col-1] == "0":
         q.put((row, col-1))
         matrix[row][col-1] = "E"
    if 0 <= row-1 and matrix[row-1][col] == "0":
         q.put((row-1, col))
         matrix[row-1][col] = "S" 
row,col=numrows-1,numcols-1
var=matrix[row][col]

show(matrix)

if var=="0":
    print ("There is no path.")
    exit()
else:
    print ("There is a path.")

# Trace the path
step = {'N': (-1, 0), 'S': (1, 0), 'E': (0, 1), 'W': (0, -1)}
while True:
    print((row, col), 'go', var)
    if row == 0 and col == 0:
        break
    r, c = step[var]
    row += r
    col += c
    var = matrix[row][col]

print('Home!')

output

0 0 0 0 1 0 0 0
0 1 1 0 1 0 1 0
0 1 0 0 1 0 1 0
0 0 0 1 0 0 1 0
0 1 0 1 0 1 1 0
0 0 1 1 0 1 0 0
1 0 0 0 0 1 1 0
0 0 1 1 1 1 0 0

E W W W 1 S W W
N 1 1 N 1 S 1 N
N 1 E N 1 S 1 N
N W W 1 S W 1 N
N 1 N 1 S 1 1 N
N W 1 1 S 1 E N
1 N W W W 1 1 N
E N 1 1 1 1 E N

There is a path.
(7, 7) go N
(6, 7) go N
(5, 7) go N
(4, 7) go N
(3, 7) go N
(2, 7) go N
(1, 7) go N
(0, 7) go W
(0, 6) go W
(0, 5) go S
(1, 5) go S
(2, 5) go S
(3, 5) go W
(3, 4) go S
(4, 4) go S
(5, 4) go S
(6, 4) go W
(6, 3) go W
(6, 2) go W
(6, 1) go N
(5, 1) go W
(5, 0) go N
(4, 0) go N
(3, 0) go N
(2, 0) go N
(1, 0) go N
(0, 0) go E
Home!



回答3:


As a variant to @程名锐's post, this implementation of a DFS will also return the first path it has found. And as a general advice, if you don't care about the path being optimal, a DFS will usually serve you better than a BFS.

Note that we also have to make sure not to run in circles, since this graph is not a tree.

# for convenience
matrix = [
    ["0", "0", "0", "0", "1", "0", "0", "0"],
    ["0", "1", "1", "0", "1", "0", "1", "0"],
    ["0", "1", "0", "0", "1", "0", "1", "0"],
    ["0", "0", "0", "1", "0", "0", "1", "0"],
    ["0", "1", "0", "1", "0", "1", "1", "0"],
    ["0", "0", "1", "1", "0", "1", "0", "0"],
    ["1", "0", "0", "0", "0", "1", "1", "0"],
    ["0", "0", "1", "1", "1", "1", "0", "0"]
]
num_rows = len(matrix)
num_cols = len(matrix[0])

# just to be a bit more flexible, could also be passed as a function argument
goal_state = (num_rows - 1, num_cols - 1)


def dfs(current_path):
    # anchor
    row, col = current_path[-1]
    if (row, col) == goal_state:
        return True

    # try all directions one after the other
    for direction in [(row, col + 1), (row, col - 1), (row + 1, col), (row - 1, col)]:
        new_row, new_col = direction
        if (0 <= new_row < num_rows and 0 <= new_col < num_cols and  # stay in matrix borders
                matrix[new_row][new_col] == "0" and                  # don't run in walls
                (new_row, new_col) not in current_path):             # don't run in circles
            # try new direction
            current_path.append((new_row, new_col))
            if dfs(current_path):  # recursive call
                return True
            else:
                current_path.pop()  # backtrack


# result a list of coordinates which should be taken in order to reach the goal
result = [(0, 0)]
if dfs(result):
    print("Success!")
    print(result)
else:
    print("Failure!")

Prints:

[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (2, 2), (3, 2), (3, 1), (3, 0), (4, 0), (5, 0), (5, 1), (6, 1), (6, 2), (6, 3), (6, 4), (5, 4), (4, 4), (3, 4), (3, 5), (2, 5), (1, 5), (0, 5), (0, 6), (0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7)]

The first (but for sure not shortest) correct path a DFS with the pathing preferences right -> left -> down -> up encounters.



来源:https://stackoverflow.com/questions/47177795/python-breadth-first-search-matrix-print-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!