牛客网IT校招编程题-逛公园-Python

题目描述:

又是晴朗的一天,牛牛的小伙伴们都跑来找牛牛去公园玩。但是牛牛想呆在家里看E3展,不想出去逛公园,可是牛牛又不想鸽掉他的小伙伴们,于是找来了公园的地图,发现公园是由一个边长为n的正方形构成的,公园一共有m个入口,但出口只有一个。公园内有一些湖和建筑,牛牛和他的小伙伴们肯定不能从他们中间穿过,所以只能绕行。牛牛想知道他需要走的最短距离并输出这个最短距离

第一行输入一个数字n(1≤n≤1000)表示公园的边长接下来会给你一个n*n的公园地图,其中 . 表示公园里的道路,表示公园的入口* 表示公园的出口,# 表示公园内的湖和建筑。牛牛和他的小伙伴们每次只能上下左右移动一格位置。输入保证公园入口个数m(1≤m≤10000)且所有的入口都能和出口相连

输入
10

    mat = [['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'],
           ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'],
           ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'],
           ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'],
           ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'],
           ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'],
           ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'],
           ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'],
           ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'],
           ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']]
输出

16

问题分析:广度优先搜索(Breadth First Search,BFS)

采用广度优先搜索的思想,首先每找到一个入口,进行一次广度优先搜索,用队列实现,但是每次出队的时候,并不是真正的出队,只让队头指针向后移动一次,这是为了,在找到出口的时候回溯到起点,以便求出最短路径,所以在入队的时候,要记录前一个结点的位置用于回溯。

Python3实现:

# 广度优先搜索,队列实现
# @Time   :2018/6/20
# @Author :LiuYinxing


def findpath(mat, n, row, col):
    path = [[1]*n for _ in range(n)]
    path[row][col] = 0  # 初始化队头
    pre = -1
    qlist = [[row, col, pre]]
    while qlist:
        pre += 1  # 出队
        i, j = qlist[pre][0], qlist[pre][1]
        if -1 < i-1:  # 上
            if path[i-1][j] == 1 and mat[i-1][j] == '.':
                qlist.append([i-1, j, pre])  # 入队
                path[i-1][j] = 0  # 标记一下,已经走过了
            elif path[i-1][j] == 1 and mat[i-1][j] == '*':  # 出口
                qlist.append([i - 1, j, pre])  # 入队
                break
        if j+1 < n:  # 右
            if path[i][j+1] == 1 and mat[i][j+1] == '.':
                qlist.append([i, j+1, pre])
                path[i][j+1] = 0
            elif path[i][j+1] == 1 and mat[i][j+1] == '*':
                qlist.append([i, j+1, pre])
                break
        if i+1 < n:  # 下
            if path[i+1][j] == 1 and mat[i+1][j] == '.':
                qlist.append([i+1, j, pre])
                path[i+1][j] = 0
            elif path[i+1][j] == 1 and mat[i+1][j] == '*':
                qlist.append([i + 1, j, pre])
                break
        if j-1 > -1:  # 左
            if path[i][j-1] == 1 and mat[i][j-1] == '.':
                qlist.append([i, j-1, pre])
                path[i][j-1] = 0
            elif path[i][j-1] == 1 and mat[i][j-1] == '*':
                qlist.append([i, j-1, pre])
                break

    fpath = [qlist[-1]]  # 回溯计算最短路径
    while pre != -1:
        fpath.append(qlist[pre])
        pre = qlist[pre][2]
    print(len(fpath)-1, fpath[::-1])
    return len(fpath)-1


def minpath(mat, n):  # 获取所有入口的最短路径,并且选择小的一个
    minpath = float('inf')
    for i in range(n):
        for j in range(n):
            if mat[i][j] == '@':
                minpath = min(findpath(mat, n, i, j), minpath)
    print('最短路径长度为:', minpath)


if __name__ == '__main__':
    n, m = 10, 4
    mat = [
        ['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'],
        ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'],
        ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'],
        ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'],
        ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'],
        ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'],
        ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'],
        ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'],
        ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'],
        ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']]
    minpath(mat, n)

Python3(简化代码):

# 广度优先搜索,队列实现
# @Time   :2018/6/20
# @Author :LiuYinxing


def findpath(mat, n, row, col):
    path = [[1]*n for _ in range(n)]
    path[row][col] = 0  # 初始化队头
    pre = -1
    qlist = [[row, col, pre]]
    while qlist:
        pre += 1  # 出队
        i, j = qlist[pre][0], qlist[pre][1]
        if checkplace(mat, path, qlist, n, pre, i-1, j): break  # 上
        if checkplace(mat, path, qlist, n, pre, i, j+1): break  # 右
        if checkplace(mat, path, qlist, n, pre, i+1, j): break  # 下
        if checkplace(mat, path, qlist, n, pre, i, j-1): break  # 左

    fpath = [qlist[-1]]  # 回溯计算最短路径
    while pre != -1:
        fpath.append(qlist[pre])
        pre = qlist[pre][2]
    print(len(fpath)-1, fpath[::-1])
    return len(fpath)-1


def checkplace(mat, path, qlist, n, pre, row, col):  # 判断新节点是否是出口
    if -1 < row < n and -1 < col < n and path[row][col] == 1:
        if mat[row][col] == '.':
            qlist.append([row, col, pre])  # 入队
            path[row][col] = 0
        elif mat[row][col] == '*':  # 出口
            qlist.append([row, col, pre])  # 入队
            return 1


def minpath(mat, n):  # 获取所有入口的最短路径,并且选择小的一个
    minpath = float('inf')
    for i in range(n):
        for j in range(n):
            if mat[i][j] == '@':
                minpath = min(findpath(mat, n, i, j), minpath)
    print('最短路径长度为:', minpath)


if __name__ == '__main__':
    n, m = 10, 4
    mat = [['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'],
           ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'],
           ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'],
           ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'],
           ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'],
           ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'],
           ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'],
           ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'],
           ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'],
           ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']]
    minpath(mat, n)
欢迎指正哦。

猜你喜欢

转载自blog.csdn.net/xx_123_1_rj/article/details/80755342