📜  门|门 CS 1996 |第 50 题(1)

📅  最后修改于: 2023-12-03 15:12:45.798000             🧑  作者: Mango

题目介绍

本题为《门》游戏中的一关,要求给出一个矩阵,计算从起点到终点的最短路径,并输出路径及其长度。本题为洛谷 P2958,POJ 1979,UVA 816。

题目分析

这道题并不是一道图论的题目,而是一道广搜的题目。矩阵中的每个格子都可以看作一个图中的节点,相邻的节点之间可以建立一条边。因此,我们可以借助广搜来解决这个问题。

广搜的流程如下:

  1. 将起点入队
  2. 当队列不为空时,取出队首节点
  3. 遍历该节点的所有相邻节点,如果相邻节点未被访问过,则将其入队,并更新相邻节点的路径和步数
  4. 当目标节点被访问到时,结束遍历

在实现广搜的过程中,我们需要借助两个数组来记录节点的路径和步数。

代码实现
#include <iostream>
#include <queue>
using namespace std;
const int MAXN = 25;
const int MAXM = 25;
int maze[MAXN][MAXM];       // 迷宫
int vis[MAXN][MAXM];        // 标记是否访问过
int dis[MAXN][MAXM];        // 记录路径长度
int pre[MAXN][MAXM][2];     // 记录前驱节点
int n, m;                   // 迷宫的行数和列数
int sx, sy, ex, ey;         // 起点和终点坐标
int dx[] = {-1, 0, 1, 0};   // 上下左右四个方向
int dy[] = {0, 1, 0, -1};

void bfs() {
    queue<pair<int, int>> q;
    q.push({sx, sy});
    vis[sx][sy] = 1;

    while (!q.empty()) {
        auto t = q.front();
        q.pop();

        for (int i = 0; i < 4; i++) {
            int nx = t.first + dx[i];
            int ny = t.second + dy[i];

            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if (maze[nx][ny] == 1) continue;
            if (!vis[nx][ny]) {
                q.push({nx, ny});
                vis[nx][ny] = 1;
                dis[nx][ny] = dis[t.first][t.second] + 1;
                pre[nx][ny][0] = t.first;
                pre[nx][ny][1] = t.second;
            }
        }
    }
}

void print_path(int x, int y) {
    if (x == sx && y == sy) {
        cout << '(' << x << ',' << y << ')' << endl;
        return;
    }

    int tx = pre[x][y][0], ty = pre[x][y][1];
    print_path(tx, ty);
    cout << '(' << x << ',' << y << ')' << endl;
}

int main() {
    while (cin >> n >> m) {
        if (n == 0) break;

        // 读入地图
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> maze[i][j];
            }
        }

        // 读入起点和终点坐标
        cin >> sx >> sy >> ex >> ey;
        sx--;
        sy--;
        ex--;
        ey--;

        // 初始化
        memset(vis, 0, sizeof(vis));
        memset(dis, 0, sizeof(dis));
        memset(pre, -1, sizeof(pre));

        // 广搜
        bfs();

        // 输出结果
        cout << "路径长度为:" << dis[ex][ey] << endl;
        cout << "路径为:" << endl;
        print_path(ex, ey);
    }

    return 0;
}
总结

本题的解法相对来说比较简单,仅仅需要掌握广搜的基本知识即可。在实现过程中,需要注意一些细节问题,例如坐标的转换以及前驱节点记录的问题。