1 条题解
-
0
自动搬运
来自洛谷,原作者为

XingnoYi
Connecting...... [ TIME_OUT ]搬运于
2025-08-24 22:56:00,当前版本为作者最后更新于2024-03-10 10:56:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
超详细的题解!
前言:
当一个音游人看到这场比赛,他的内心……这题调了足足 个小时,全是细节错误。
要不是 VS Code,我估计这辈子都调不出来。
如下
big代表long long。思路分析:
子问题 :
问题简述:找出起点到终点的最短路径长度。
这应该很好想,就是一道 BFS 的模板题,和 P1141 01迷宫 比较相似。
如果你不会 BFS,可以看一下概述。
子问题 :
问题概述:输出该最短路径的行走方式。
在纯 BFS 中应该无法直接回溯找到路径的。
1. 数组:
我们可以加入数组 ,该数组表示这个格子是由上一个格子从什么方向到达的,以方便路径逆推。
用样例举例:
01 10该图的一种 数组表示如下:
0 R D D你会发现,这幅图最短路径的的走法就是 ,即
RD。你也许会问:这只是起点到终点的走法,那 BFS 最后已经到终点了,怎么用这个数组来找路径呢?
2. 逆推求路径:
想一想,你走到终点了,那只需要从终点开始,记录每个点的 值,再往反方向走,直到走回起点为止。
这样,只需要将记录的 值反向输出即可。
如何反向输出?
可以用栈或字符串。
我使用的是栈的方法。
同样地,以该图举例:
0 R D D- 最开始我们在 。
- 此时,,我们可以将其压入栈中。
D方向的反方向为U,于是我们向上走,回到 。- 重复 和 操作直到回到 。
BFS 函数的代码:
void bfs(big sx,big sy) // bfs 模板 { queue <Node> q; q.push(Node({sx,sy})); dis[sx][sy] = 0; vis[sx][sy] = 1; while(!q.empty()) { Node pos=q.front(); q.pop(); if(pos.x == n && pos.y == m) { printf("%lld\n",dis[n][m]); // 因为需要逆序输出,这里用一个栈存储路径。 // 用字符串反向输出也可以。 stack <big> st; big ex = n,ey = m; while((ex != 1) || (ey != 1)) { st.push(ways[ex][ey]); // 正向存储 big back = (ways[ex][ey]+2)%4; // 反向回溯 ex += to[back][0], ey += to[back][1]; // 回溯 } while(!st.empty()) { putchar(path[st.top()]); // 反向输出路径 st.pop(); } putchar('\n'); return; } big ax = pos.x, ay = pos.y; for(big i = 0;i < 4;i++) { big nowx = ax+to[i][0], nowy = ay+to[i][1]; if((vis[nowx][nowy] == 0) && (mapp[nowx][nowy] != mapp[ax][ay]) && (1 <= ax && ax <= n && ay >= 1 && ay <= m)) { ways[nowx][nowy] = i; dis[nowx][nowy] = dis[ax][ay]+1; vis[nowx][nowy] = 1; q.push(Node({nowx,nowy})); } } } // 若没有到终点就无法继续了,说明无解。 printf("-1\n"); }坑点简述:
气死我了……坑点 :
关于方向数组,一般有 种写法:
- 用 个数组存 和 。
- 用 个二维数组同时存一个数对 。
当使用第 种方向时,一定要注意数组两个维度的定义。
对比如下代码:
to[4][2]={1,0,0,1,-1,0,0,-1}; big nowx = ax+to[i][0], nowy = ay+to[i][1];to[2][4]={1,0,0,1,-1,0,0,-1}; big nowx = ax+to[0][i], nowy = ay+to[1][i];乍一看是不是没什么区别?
其实第一种是对的。


看一下 VS Code 中对两种数组的概况描述。
to[4][2]这种定义是一个 行 列的数组,每行存一个数对 ,表示增减值。而
to[2][4]这种定义是一个 行 列的数组,每行存一个数组,分别表示 和 。很显然,第二种方案的 就变成了:
(1,-1) (0,0) (0,0) (1,-1)是错误的。
一般来说,我们都会输入 个数对,而不是分两行输入,所以我推荐用 来存储。
坑点 :
多测清空时不要用
memset(),也不要直接全部清空。应该先确定大小再清空。
坑点 :
在循环判断是否回到起点时,所用的判断条件为:
while((ex != 1) || (ey != 1)) // 坑点3:用或而不是且。不过要很好地避免此类问题,可以用:
while(!((ex == 1) && (ey == 1)))完整代码:
#include <iostream> #include <queue> #include <stack> #define big long long using namespace std; struct Node{ big x,y; }; big T,n,m,to[4][2]={1,0,0,1,-1,0,0,-1}; // 坑点1:方向数组应用。二维数组应用 [4][2] 而不是 [2][4]。 char path[5]={'D','R','U','L'}; // 方向要对应,为简化代码,采用逆时针存储方向。 big ways[3004][3004],dis[3004][3004]; // ways[i][j] 表示这个格子是由上一个格子从什么方向到达的(以方便路径逆推)。 // dis[i][j] 表示该点到起点的距离。 bool vis[3004][3004],mapp[3004][3004]; // 是否到达过;存地图 void bfs(big sx,big sy) // bfs 模板 { queue <Node> q; q.push(Node({sx,sy})); dis[sx][sy] = 0; vis[sx][sy] = 1; while(!q.empty()) { Node pos=q.front(); q.pop(); if(pos.x == n && pos.y == m) { printf("%lld\n",dis[n][m]); // 因为需要逆序输出,这里用一个栈存储路径。 // 用字符串反向输出也可以。 stack <big> st; big ex = n,ey = m; while((ex != 1) || (ey != 1)) // 坑点3:用或而不是且。 { st.push(ways[ex][ey]); // 正向存储 big back = (ways[ex][ey]+2)%4; // 反向回溯 ex += to[back][0], ey += to[back][1]; // 回溯 } while(!st.empty()) { putchar(path[st.top()]); // 反向输出路径 st.pop(); } putchar('\n'); return; } big ax = pos.x, ay = pos.y; for(big i = 0;i < 4;i++) { big nowx = ax+to[i][0], nowy = ay+to[i][1]; if((vis[nowx][nowy] == 0) && (mapp[nowx][nowy] != mapp[ax][ay]) && (1 <= ax && ax <= n && ay >= 1 && ay <= m)) { ways[nowx][nowy] = i; dis[nowx][nowy] = dis[ax][ay]+1; vis[nowx][nowy] = 1; q.push(Node({nowx,nowy})); } } } // 若没有到终点就无法继续了,说明无解。 printf("-1\n"); } int main() { scanf("%lld\n",&T); while(T--) { scanf("%lld %lld\n",&n,&m); // 坑点2:先输入再清空,降低复杂度。 for(big i = 0;i <= n;i++) { for(big j = 0;j <= m;j++) { vis[i][j] = 0; dis[i][j] = ways[i][j] = 0; } } for(big i = 1;i <= n;i++) { for(big j = 1;j <= m;j++) { // 注意读入 '\n' 导致答案错误 char ch = getchar(); while(ch != '0' && ch != '1') { ch = getchar(); } mapp[i][j] = ch-'0'; } } if((mapp[n-1][m] == mapp[n][m]) && (mapp[n][m-1] == mapp[n][m])) // 小小优化 { printf("-1\n"); continue; } bfs(1,1); } return 0; }
- 1
信息
- ID
- 9766
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者