P1746 离开中山路
题目背景
《爱与愁的故事第三弹·shopping》最终章。
题目描述
爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在 x1,y1 处,车站在 x2,y2 处。现在给出一个 n×n(n≤1000) 的地图,0 表示马路,1 表示店铺(不能从店铺穿过),爱与愁大神只能垂直或水平着在马路上行进。爱与愁大神为了节省时间,他要求最短到达目的地距离(每两个相邻坐标间距离为 1)。你能帮他解决吗?
输入格式
第 1 行包含一个数 n。
第 2 行到第 n+1 行:整个地图描述(0 表示马路,1 表示店铺,注意两个数之间没有空格)。
第 n+2 行:四个数 x1,y1,x2,y2。
输出格式
只有 1 行,即最短到达目的地距离。
输入输出样例
输入
3
001
101
100
1 1 3 3
输出
4
说明/提示
对于 20% 数据,满足 1≤n≤100。
对于 100% 数据,满足 1≤n≤1000。
代码
#include <bits/stdc++.h>
#define N 1010 // 定义地图最大尺寸为 1010 (题目中 n ≤ 1000,留出额外空间)
using namespace std;
int dist[N][N]; // 存储从起点到各个位置的最短距离,初始化为 -1 表示未访问
char g[N][N]; // 地图数组,每个字符表示一个位置,'0' 表示马路(可通过),'1' 表示店铺(不可通过)
typedef pair<int,int> PII; // 定义一个 pair 类型,用于存储坐标 (行, 列)
queue<PII> q; // 定义队列用于 BFS 算法
int n; // 地图的尺寸(地图为 n×n)
int dx[] = {1, -1, 0, 0}; // 四个方向移动的行偏移量:下、上、右、左
int dy[] = {0, 0, 1, -1}; // 四个方向移动的列偏移量
int x1, Y1, x2, y2; // 起点坐标 (x1, Y1) 和目的地坐标 (x2, y2)
// BFS 函数:从起点搜索最短路径到目的地
int bfs(int x, int y) {
// 初始化距离数组为 -1,表示所有位置均未访问
memset(dist, -1, sizeof(dist));
// 将起点 (x1, Y1) 入队,并将起点距离设为 0
q.push({x1, Y1});
dist[x1][Y1] = 0;
// 当队列不为空时,进行 BFS 搜索
while (!q.empty()) {
// 取出队头元素,当前正在探索的位置
auto t = q.front();
q.pop();
// 遍历四个可能的移动方向
for (int i = 0; i < 4; i++) {
int a = t.first + dx[i]; // 计算新位置的行号
int b = t.second + dy[i]; // 计算新位置的列号
// 判断新位置是否超出地图边界(注意坐标从 1 开始)
if (a < 1 || b < 1 || a > n || b > n)
continue;
// 判断新位置是否为马路(只有 '0' 才可通行)
if (g[a][b] != '0')
continue;
// 若该位置已经访问过,则跳过
if (dist[a][b] >= 0)
continue;
// 将新位置加入队列等待后续探索
q.push({a, b});
// 更新新位置的距离:当前节点距离加 1
dist[a][b] = dist[t.first][t.second] + 1;
// 如果目的地 (x2, y2) 已经被访问,则直接返回最短距离
if (dist[x2][y2] > 0)
return dist[x2][y2];
}
}
// 如果搜索结束仍未访问到目的地,返回 -1 表示不可达
return -1;
}
int main() {
// 读入地图尺寸 n
scanf("%d", &n);
// 读入地图,每行输入一个字符串,注意字符串下标从 1 开始存储到数组 g 中
for (int i = 1; i <= n; i++) {
scanf("%s", g[i] + 1);
}
// 读入起点和目的地的坐标:x1, Y1 为起点;x2, y2 为目的地
scanf("%d %d %d %d", &x1, &Y1, &x2, &y2);
// 调用 BFS 函数计算最短路径距离
int res = bfs(x1, Y1);
// 输出最短路径距离,若不可达则输出 -1
printf("%d\n", res);
return 0;
}
题目《P1746 离开中山路》描述了如下情境:
-
给出一个
n×nn \times nn×n
的地图,地图上每个位置用字符表示,
'0'
表示马路(可以通行),'1'
表示店铺(不能穿过)。
-
起点位于 (x1,y1)(x_1, y_1)(x1,y1),车站(目的地)位于 (x2,y2)(x_2, y_2)(x2,y2)。
-
只能沿水平方向或垂直方向行走(每步距离为 1),要求求出从起点到目的地的最短距离,若无法到达则输出 -1。
2. 建模与数据结构
- 地图表示
使用二维字符数组g[][]
存储地图,数组下标从 1 开始便于与题目描述对应。 - 距离记录
使用二维整型数组dist[][]
存储从起点到每个位置的最短步数,初始化为 -1 表示该位置还未被访问过。 - 队列
为实现广度优先搜索(BFS),使用 STL 中的queue
存储待探索的位置。
3. 算法选择:广度优先搜索 (BFS)
-
原因
BFS 能够在无权图中(每步代价均为 1)快速找到从起点到任意位置的最短路径。 -
步骤
-
初始化
- 将起点 (x1,Y1)(x_1, Y_1)(x1,Y1) 的距离设为 0,并将其放入队列。
-
搜索过程
- 每次从队列中取出一个节点,依次检查其上下左右四个相邻位置。
- 对每个相邻位置,进行以下判断:
- 是否在地图范围内;
- 是否为马路(只有
'0'
可通行); - 是否已经访问过。
- 若满足条件,则更新该位置的距离(当前节点的距离加 1),并将其加入队列。
- 若目的地 (x2,y2)(x_2, y_2)(x2,y2) 被访问,则可以提前返回最短距离。
-
结束条件
- 如果队列为空仍未能到达目的地,则说明目的地不可达,返回 -1。
-