You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
3.3 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}