#P2282. 第1题-铺设光缆问题
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 1484
            Accepted: 390
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2024年10月9日-国内
                              
                      
          
 
- 
                        算法标签>BFS          
 
第1题-铺设光缆问题
题面解释
某运营商计划在一个用m∗n矩阵表示的区域内铺设光缆,起点为机房,终点为目标小区。光缆只能沿着矩阵的边铺设(不能走对角线),部分节点由于各种原因无法经过(如输入中的障碍节点)。机房和小区的坐标可以位于矩阵内的任何位置。任务是计算从机房到小区铺设光缆的最短距离,如果无法到达,则返回−1。
思路:BFS求最短路
本题大意为:给你一个二维矩阵,里面有若干个点不能通过,求起点到终点的最短距离。
这题是一个非常朴素的BFS求最短路。咱们的题单里大量考察了这个知识点,刷过的同学基本就能通过啦~
题解分析:
1. BFS的思想:
广度优先搜索(BFS)是解决无权图最短路径问题的经典算法。它的基本思想是:
- 从起点开始,将其加入队列,并标记距离为0。
 - 每次从队列中取出一个点,尝试从该点向四个方向扩展(上下左右),并检查扩展的点是否满足条件:
- 新的点在矩阵范围内;
 - 新的点不是障碍物;
 - 新的点没有被访问过。
 
 - 如果条件都满足,则将该点加入队列,并将其距离更新为当前点的距离加1。
 - 当队列为空时,算法结束,最终记录终点的距离。
 
2. 具体实现步骤:
- 输入数据的处理:首先读入矩阵的大小m和n,起点和终点的坐标,以及障碍点的数量和位置。我们使用一个二维数组
grid来表示矩阵,其中0表示可经过的点,1表示障碍点。 - 距离数组的初始化:使用一个二维数组
dist来记录每个点到起点的最短距离。初始时将dist数组全部设置为-1,表示所有点都未访问过。 - BFS过程:
- 从起点开始,将起点坐标放入队列,并将其距离设为0。
 - 然后每次从队列中取出一个点,检查它的四个相邻点是否可以继续前进(不越界、不是障碍且未访问过),如果可以,则将其加入队列并更新其距离。
 
 - 输出结果:在BFS完成后,输出终点的最短距离。如果终点的距离仍为-1,说明无法到达终点。
 
3. 边界情况考虑:
- 障碍点完全堵死路径:如果起点和终点被障碍点完全围住,BFS过程中终点的距离不会被更新,最终返回-1。
 - 起点与终点重合:如果起点和终点相同,那么直接输出距离0。
 - 矩阵边界的处理:BFS扩展时需注意检查新的点是否在矩阵的边界内,防止越界访问。
 
4. 复杂度分析:
- 时间复杂度:BFS的时间复杂度是O(m∗n),其中m和n是矩阵的长和宽,因为每个点最多被访问一次。
 - 空间复杂度:空间复杂度同样为O(m∗n),因为我们需要记录每个点的距离以及队列中的点。
 
代码
x代表行数(纵坐标),y代表列数(横坐标)。左上角是(0,0)
java
import java.util.*;
public class Main {
    static int n, m;
    static int[][] grid;
    static int[][] dist;
    static int[] dx = {0, 0, 1, -1}; // 移动方向,分别为右、左、下、上
    static int[] dy = {1, -1, 0, 0}; // 移动方向,分别为右、左、下、上
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        m = sc.nextInt();
        n = sc.nextInt();
        int sy = sc.nextInt();
        int sx = sc.nextInt();
        int ey = sc.nextInt();
        int ex = sc.nextInt();
        grid = new int[n][m];
        dist = new int[n][m];
        // 初始化距离数组为-1,表示尚未访问
        for (int i = 0; i < n; i++) {
            Arrays.fill(dist[i], -1);
        }
        int k = sc.nextInt(); // 不可通过的障碍点数量
        for (int i = 0; i < k; i++) {
            int y = sc.nextInt();
            int x = sc.nextInt();
            grid[x][y] = 1; // 设置障碍点
        }
        // 调用BFS寻找最短路径
        bfs(sx, sy);
        // 输出终点到起点的最短距离
        System.out.println(dist[ex][ey]);
    }
    // BFS算法实现
    static void bfs(int sx, int sy) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{sx, sy});
        dist[sx][sy] = 0;
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int x = current[0];
            int y = current[1];
            // 遍历四个方向
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                // 判断新的位置是否在矩阵范围内,且未访问且不是障碍
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && dist[nx][ny] == -1 && grid[nx][ny] == 0) {
                    queue.add(new int[]{nx, ny});
                    dist[nx][ny] = dist[x][y] + 1; // 更新距离
                }
            }
        }
    }
}
python
m = int(input())
n = int(input())
sy, sx = map(int, input().split())
ey, ex = map(int, input().split())
arr = [[0 for _ in range(m)] for _ in range(n)]  # 初始化地图矩阵
k = int(input())  # 障碍点数量
for _ in range(k):
    y, x = map(int, input().split())
    arr[x][y] = 1  # 标记障碍点
dx = [0, 0, 1, -1]  # 方向数组,分别表示右、左、下、上
dy = [1, -1, 0, 0]  # 方向数组,分别表示右、左、下、上
dist = [[-1 for _ in range(m)] for _ in range(n)]  # 初始化距离矩阵为-1
def bfs(x, y):
    q = []
    q.append([x, y])
    dist[x][y] = 0  # 起点距离为0
    while q:
        x, y = q.pop(0)
        for i in range(4):  # 遍历四个方向
            nx, ny = x + dx[i], y + dy[i]
            if 0 <= nx < n and 0 <= ny < m and dist[nx][ny] == -1 and arr[nx][ny] == 0:
                q.append([nx, ny])
                dist[nx][ny] = dist[x][y] + 1  # 更新距离
bfs(sx, sy)
print(dist[ex][ey])  # 输出终点的最短距离
cpp
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
int n, m;
int grid[1000][1000];
int dist[1000][1000];
int dx[4] = {0, 0, 1, -1}; // 方向数组:右、左、下、上
int dy[4] = {1, -1, 0, 0}; // 方向数组:右、左、下、上
// BFS算法
void bfs(int sx, int sy) {
    queue<pair<int, int>> q;
    q.push({sx, sy});
    dist[sx][sy] = 0;
    while (!q.empty()) {
        auto [x, y] = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            // 检查新的位置是否在矩阵内且未访问且不是障碍
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && dist[nx][ny] == -1 && grid[nx][ny] == 0) {
                q.push({nx, ny});
                dist[nx][ny] = dist[x][y] + 1;  // 更新距离
            }
        }
    }
}
int main() {
    cin >> m >> n;
    int sx, sy, ex, ey;
    cin >> sy >> sx >> ey >> ex;
    memset(grid, 0, sizeof(grid));
    memset(dist, -1, sizeof(dist));  // 初始化距离数组为-1
    int k;  // 障碍数量
    cin >> k;
    for (int i = 0; i < k; i++) {
        int x, y;
        cin >> y >> x;
        grid[x][y] = 1;  // 设置障碍点
    }
    bfs(sx, sy);
    cout << dist[ex][ey] << endl;  // 输出终点到起点的最短距离
    return 0;
}
OJ会员可以通过点击题目上方《已通过》查看其他通过代码来学习。
题目内容
某运营商需要在某一区城铺设光缆,起点为机房,终点为某小区,整个区域以一个m∗n的矩阵表示,光缆沿着矩阵的边铺设(不允许走对角线),区域内有些节点可以经过,但有些节点(如图红色x的位置,输入时给定) 因为各种因素无法经过,起点的机房与终点的小区可能在区域内的任何位置,计算从机房到目标小区铺设光缆的最短距离(如果光缆无法从起点机房铺设到达目标小区,返回−1)。

输入描述
m矩阵宽(横轴点数量,例如图示为11,以0~10作为下标)
n矩阵高(纵轴点数量,例如图示为8,以0~7作为下标)
机房坐标(a1,a2)
目标小区坐标(b1,b2)
矩阵内不允许经过的节点数量k
依次为这些不允许经过的节点坐标
1<=m,n<=1000
0<=k<=100000
输出描述
从机房到目标小区铺设光缆的最短距离
样例1
输入
11
8
2 3
7 5
6
2 4
3 5
4 4
5 4
6 4
7 4
输出
9
说明
11∗8的矩阵(横轴坐标0~10,纵轴坐标0~7)
起始点(机房)为坐标(2 3)
目标点(要连到的小区)为坐标(7 5)
矩阵内不允许经过的节点数为6个
依次给出这些不允许经过的节点坐标
样例2
输入
3
3 
0 0
2 2
3
0 1
1 1
2 1
输出
-1
说明
3∗3的矩阵
起始点(机房)为坐标(0 0)
目标点(要连到的小区)为坐标(2 2)
矩阵内不允许经过的节点数为3个
依次给出这些不允许经过的节点坐标