实习笔试准备(3)

1 第三题

1.1 题目描述

给定一个迷宫,找到最快从起点到达重点的路径所需要的步数。 假设迷宫如下,假定左上角坐标为(0, 0),右下角坐标为(3, 2)

1 0 -1 1

-2 0 -1 -3

2 2 0 0

-2是迷宫的起点,坐标为(0, 1)

-3是迷宫的终点,坐标为(3, 1)

-1代表障碍物,不能行走

1和2代表传送门,传送门门由正整数标示,只会成对出现。站在传送门上,能仅用一步就传送到相同数字的另一个传送i门的位置: 1只能传送到1, 2只能传送到2。站在传送门上也可以选择不传送。

从起点到终点有若干种走法,举例如下:

(0,1)->(1,1)->(1,2)->(2,2)->(3,2)->(3, 1),共花费5步

或者

(0,1)->(0, 0) -传送> (3,0)->(3,1),共花费3步 经检验3步是所需的最少步数,最后结果返回3。

1.2 输入描述

每一行输入都是用空格隔开的整数

第一行给出迷宫地图的长和宽,均为正整数

之后每一行的每一个数字,都代表迷宫的一格

-2表示起点,-3表示终点,-1表示不可通过的障碍物,0表示可通过的道路,大于0的正整数代表传送门,并且保证成对出现,在传送门上,可以仅用一步传送到另一一个相同数字的传送门]的位置。

1.3 输出描述

输出最少要多少步能够从起点走到终点。

输出-1如果没有任何办法从起点走到终点。

1.4 测试用例

1.4.1 input

4 3
1  0 -1  1
-2 0 -1 -3
2  2  0  0

1.4.2 output

3

1.5 代码示例 

def find_shortest_path(m):
    r = len(m)  # 行数
    c = len(m[0])  # 列数 迷宫第一行的长度

    # 将start和end的初始值设为None
    start = None
    end = None

    # 遍历迷宫的每个位置,找到起点和终点的坐标
    for i in range(r):
        for j in range(c):
            if m[i][j] == -2:
                start = (i, j)
            elif m[i][j] == -3:
                end = (i, j)
    # 检查起点和终点是否成功找到,如果没有找到,则返回-1
    if not start or not end:
        return -1

    # 定义四个方向的移动,右移,左移,下移,上移
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

    queue = [(start, 0)]  # 使用队列进行广度优先搜索  队列
    visited = {start}  # 记录已经访问过的位置  集合

    while queue:   # 队列不为空,执行循环
        current, steps = queue.pop(0)   # 取出队列中的第一个元素(current, steps),current表示当前格子坐标,steps表示到达当前格子所用的步数

        if current == end:  # 如果当前格子坐标等于终点坐标end,说明已经找到了最短路径,直接返回steps
            return steps

        for direction in directions:  # 当前格子不是终点,则对当前格子的四个相邻格子进行遍历
            next_pos = (current[0] + direction[0], current[1] + direction[1])  # 当前位置的横坐标+direction的横坐标,当前位置的纵坐标+direction的纵坐标

            if 0 <= next_pos[0] < r and 0 <= next_pos[1] < c:  # 判断next_pos是否在迷宫范围内
                if m[next_pos[0]][next_pos[1]] != -1 and next_pos not in visited:  # 判断next_pos是否可以通过(障碍物)及是否已经被访问过
                    queue.append((next_pos, steps + 1))  # 添加到队列,更新steps
                    visited.add(next_pos)  # 添加到已访问集合中

    return -1


# 读取迷宫地图
rows, cols = map(int, input("请输入迷宫地图的长和宽,以空格分隔:").split())  # 输入行数 列数,空格分隔,将分割后的字符串转换为整数,然后赋值给rows和cols.
maze = []  # 空列表,用于存储迷宫地图
for _ in range(rows):
    row = list(map(int, input("请输入迷宫每行的格子值,以空格分隔:").split()))  # 逐行读取迷宫地图
    maze.append(row)  # 将每一行添加到maze列表中

# 计算最少步数
shortest_steps = find_shortest_path(maze)

# 输出结果
print("最少要走的步数:", shortest_steps)

1.5.1 input

请输入迷宫地图的长和宽,以空格分隔:3 4
请输入迷宫每行的格子值,以空格分隔:1 0 -1 1
请输入迷宫每行的格子值,以空格分隔:-2 0 -1 -3
请输入迷宫每行的格子值,以空格分隔:2 2 0 0

1.5.2 output

最少要走的步数: 5

2 代码解释

2.1 current, steps = queue.pop(0)

这行代码从队列 queue 中取出第一个元素,并将其分解为 currentsteps 两个变量。队列是一种先进先出的数据结构,通过 pop(0) 操作可以取出队列中的第一个元素。在这里,current 表示当前所在的位置,steps 表示从起点到达当前位置所经过的步数。这样,我们可以在后续的操作中使用 currentsteps 来进行路径搜索和步数计算。

2.2 queue.append((next_pos, steps + 1)) 

queue.append((next_pos, steps + 1))
visited.add(next_pos)

在这段代码中,我们将下一个位置 next_pos 和当前步数 steps + 1 组成一个元组 (next_pos, steps + 1),并将其添加到队列 queue 中。这表示我们将继续以下一个位置为起点,步数加1的方式进行搜索。

同时,我们将下一个位置 next_pos 添加到集合 visited 中,表示该位置已经被访问过。这样可以避免重复访问同一个位置,以提高搜索效率。

通过以上操作,我们实现了广度优先搜索算法中的扩展操作,将下一个可行的位置加入队列,并标记为已访问。这样可以保证在搜索过程中不会遗漏任何可行的路径,并且不会陷入无限循环。

appendadd 是不同的方法,用于在不同的数据结构中添加元素。

  • append列表(List)对象的方法,用于在列表末尾添加一个元素。在上述代码中,我们使用 queue.append((next_pos, steps + 1)) 将一个元组添加到队列的末尾。

  • add集合(Set)对象的方法,用于向集合中添加一个元素。在上述代码中,我们使用 visited.add(next_pos) 将下一个位置添加到已访问的集合中。

两者的区别在于,append 是针对列表的操作,将元素添加到列表的末尾;而 add 是针对集合的操作,将元素添加到集合中

猜你喜欢

转载自blog.csdn.net/aaaccc444/article/details/131133948