Files
python/TangDou/AcWing/MiniPath/1076_1.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

73 lines
3.3 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
// 边权为1的时候,可以使用bfs求最短路径
// 学习:bfs中如何记录路径,就是把bool st[N][N]修改为pair类型,记录前序是哪个点
// 这样,st就不光可以记录走没走过(没走过的话,值为空,走过的话有PII值),而且可以通过PII反推回走的路线
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 1010, M = N * N;
int n;
int g[N][N]; // 地图,1是墙壁,0是可以走的路,4个方向可以走
PII pre[N][N];
// 前序坐标,每个位置,都需要记录它的前序来源坐标,
// 如果来源坐标还是默认的初始值-1,表示没有走过;如果来源坐标里有一个数对,就知道它是由某个位置走过来的,就是走过了
// 参数:x,y 坐标,值:前驱是哪个节点PII,相当于一个PII组成的链条,从最后一个出发,不断的找自己的前驱,就可以找到起点
// 配合一个 while(true)的循环,不断的向前找前驱,就可以走完最短路径的全程,至于是不是反了
// 背一下结论: 
// 倒着推:while(true)直接输出
// 正着推:需要配合vecotr<PII>进行一次暂存,然后再倒序输出即可
int dx[] = {-1, 0, 1, 0}; // 上右下左
int dy[] = {0, 1, 0, -1}; // 上右下左
// bfs的特点决定它第一次找到的出口点,就是最短路径
PII q[M]; // 队列
void bfs(int sx, int sy) {
// 将起始点初始化到队列中
int hh = 0, tt = -1;
q[++tt] = {sx, sy};
// 初始化一个不存在的值,用以区分是不是走过了
// 这个memset很牛X的样子,可以把一个数组+结构体 中的数据全部初始化为-1!
memset(pre, -1, sizeof pre); // 利用pre数组来防止走回头路
pre[sx][sy] = {0, 0}; // 最后一个位置(n-1,n-1)只要设置一个非-1的值,就描述它走过了,防止重复走
while (hh <= tt) {
PII t = q[hh++];
for (int i = 0; i < 4; i++) {
int x = t.x + dx[i], y = t.y + dy[i];
if (x < 0 || x >= n || y < 0 || y >= n) continue; // 不越界
if (g[x][y]) continue; // 墙壁
if (~pre[x][y].x) continue; // 走过
// 可以走
q[++tt] = {x, y}; // 将可以走的点入队列
pre[x][y] = t; // 记录从t可以走到{x,y}
}
}
}
int main() {
cin >> n;
// 本题要求左上角是(0,0),下标不能从1开始
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> g[i][j];
// 因为每个节点都记录的是自己的上一步是谁,但没有记录自己的下一步是谁
// 所以,如果是正向搜索,从(0,0)出发,(0,0)不知道自己的下一步是哪个位置!
// 如果倒着搜索,从(n-1,n-1)出发,则遍历到的每个位置坐标(x,y),都知道自己的前序是谁,
// 一直到(0,0),(0,0)也就知道了自己的前序节点是哪个,这是一个通用的套路
bfs(n - 1, n - 1);
// 输出路径
PII start = {0, 0};
while (true) {
printf("%d %d\n", start.x, start.y);
if (start.x == n - 1 && start.y == n - 1) break;
start = pre[start.x][start.y];
}
return 0;
}