题解:AtCoder AT_awc0083_d Escape from the Ice Rink
【题目来源】
AtCoder:D - Escape from the Ice Rink
【题目描述】
Takahashi is trapped in a rectangular ice rink with \(H\) rows and \(W\) columns. There are \(N\) pillars standing inside the rink. The \(i\)-th pillar is located at coordinates \((R_i, C_i)\). Here, coordinates \((r, c)\) denote the cell in the \(r\)-th row from the top and the \(c\)-th column from the left.
Takahashi is currently at the top-left corner at coordinates \((1, 1)\) and aims to reach the goal at the bottom-right corner at coordinates \((H, W)\).
The ice on the rink is extremely slippery, and once he starts sliding, he cannot change direction or stop midway. In one move, Takahashi chooses one of the four directions — up, down, left, or right — and begins sliding, continuing straight in that direction until one of the following conditions is met:
- Reaching the edge of the rink: Since he cannot go outside the rink, he stops at the edge cell.
- Reaching the cell just before a pillar: If the next cell in the sliding direction contains a pillar, he cannot enter the cell with the pillar, so he stops at the cell just before it.
Here, up means the direction of decreasing row number, down means increasing row number, left means decreasing column number, and right means increasing column number.
If he cannot advance even one cell in the chosen direction (i.e., the adjacent cell contains a pillar, or he is already at the edge of the rink and no cell exists in that direction), Takahashi does not move and stays at his current cell. This still counts as one move.
Takahashi may visit the same cell any number of times.
Find the minimum number of moves required for Takahashi to start from coordinates \((1, 1)\) and stop at coordinates \((H, W)\). Stopping at coordinates \((H, W)\) means that, following the movement rules described above, he comes to a stop at coordinates \((H, W)\). Simply passing through coordinates \((H, W)\) while sliding does not count as reaching the goal.
If it is impossible to reach the goal, output -1.
It is guaranteed that there are no pillars at coordinates \((1, 1)\) or coordinates \((H, W)\).
高桥被困在一个 \(H\) 行 \(W\) 列的矩形滑冰场中。冰场内有 \(N\) 个柱子。第 \(i\) 个柱子的坐标为 \((R_i, C_i)\)。这里,坐标 \((r, c)\) 表示从上往下数第 \(r\) 行、从左往右数第 \(c\) 列的单元格。
高桥目前位于左上角坐标 \((1, 1)\) 处,目标是到达右下角坐标 \((H, W)\) 处的终点。
冰面上的冰非常滑,一旦他开始滑动,他就不能改变方向或中途停止。在一次移动中,高桥选择四个方向之一——上、下、左、右——并开始滑动,一直沿该方向直线滑动,直到满足以下条件之一:
- 到达冰场边缘:由于他不能离开冰场,他在边缘单元格处停止。
- 到达柱子前一个单元格:如果滑动方向的下一个单元格包含柱子,他不能进入柱子所在的单元格,因此他会在柱子之前的单元格停止。
这里,上是指行号减少的方向,下是指行号增加的方向,左是指列号减少的方向,右是指列号增加的方向。
如果他在所选方向上甚至无法前进一个单元格(即相邻单元格包含柱子,或者他已经处于冰场边缘且该方向上没有单元格),高桥不会移动并停留在当前单元格。这仍然算作一次移动。
高桥可以多次访问同一个单元格。
求高桥从坐标 \((1, 1)\) 出发,停止在坐标 \((H, W)\) 所需的最少移动次数。停止在坐标 \((H, W)\) 意味着,按照上述移动规则,他停在了坐标 \((H, W)\) 处。仅仅在滑动过程中经过坐标 \((H, W)\) 不算到达终点。
如果无法到达终点,输出 -1。
保证坐标 \((1, 1)\) 和坐标 \((H, W)\) 处没有柱子。
【输入】
\(H\) \(W\) \(N\)
\(R_1\) \(C_1\)
\(R_2\) \(C_2\)
\(\vdots\)
\(R_N\) \(C_N\)
- The first line contains \(H\), the number of rows of the ice rink, \(W\), the number of columns, and \(N\), the number of pillars, separated by spaces.
- The following \(N\) lines contain the coordinates of each pillar. If \(N = 0\), this part does not exist.
- The \((1 + i)\)-th line (\(1 \leq i \leq N\)) contains the row number \(R_i\) and column number \(C_i\) of the \(i\)-th pillar, separated by spaces.
【输出】
Print in one line the minimum number of moves required for Takahashi to stop at coordinates \((H, W)\) starting from coordinates \((1, 1)\). If it is impossible, print -1.
【输入样例】
3 3 1
2 2
【输出样例】
2
【核心思想】
-
问题分析:高桥从 \((1, 1)\) 出发,每次选择一个方向滑动,直到碰到边界或柱子才停止,求到达 \((H, W)\) 的最少移动次数。这是一个BFS + 滑动扩展问题,关键在于每次移动不是走一步,而是沿一个方向滑动到最远可达位置。
-
算法选择:
- BFS(广度优先搜索):按层遍历,第一次到达终点的移动次数即为最少移动次数
- 滑动扩展:对于每个方向,使用 while 循环模拟滑动过程,直到碰到边界或柱子
- 障碍物映射表
mp:使用map<PII, int>存储柱子位置,实现 \(O(\log N)\) 查询
-
关键步骤:
- 初始化:读取 \(H\)(行数)、\(W\)(列数)、\(N\)(柱子数),建立障碍物映射表
- BFS搜索:
- 起点 \((1, 1)\) 入队,距离设为 \(0\)
- 对于每个出队节点,遍历四个方向
- 滑动模拟:沿当前方向一直滑动,直到:
- 超出边界(\(tx < 1\) 或 \(tx > H\) 或 \(ty < 1\) 或 \(ty > W\))
- 遇到柱子(
mp.count({tx, ty})为真)
- 记录滑动终点 \((nx, ny)\)
- 如果终点未访问过,更新距离并入队
- 输出结果:如果
dist[H][W]为无穷大,输出 \(-1\);否则输出最短距离
-
时间/空间复杂度:
- 时间复杂度:\(O(H \times W \times (H + W))\),每个格子最多访问一次,每次滑动最多经过 \(H + W\) 个格子
- 空间复杂度:\(O(H \times W + N)\),需要存储距离数组、队列、障碍物映射表
-
BFS + 滑动扩展的核心思想:
- 滑动模拟:每次移动不是单步移动,而是沿一个方向滑动到最远可达位置
- 状态转移:从当前位置 \((x, y)\) 可以转移到四个滑动终点
- 边界检测:实时检测是否超出网格边界或遇到障碍物
- 最短路径保证:BFS保证第一次到达终点的路径移动次数最少
- 适用于冰壶、滑行迷宫、光滑表面移动类问题
【算法标签】
BFS-二维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII; // 定义坐标对类型
const int N = 105; // 定义网格最大尺寸
int h, w, n; // 网格高度h,宽度w,障碍物数量n
int dist[N][N]; // 距离数组,存储到每个格子的最短距离
int dx[4] = {-1, 1, 0, 0}; // 四个方向的x偏移:上下左右
int dy[4] = {0, 0, -1, 1}; // 四个方向的y偏移:上下左右
map<PII, int> mp; // 障碍物映射表,存储障碍物位置
void bfs() // 广度优先搜索函数
{
memset(dist, 0x3f, sizeof(dist)); // 初始化所有距离为无穷大
dist[1][1] = 0; // 起点距离为0
queue<PII> q; // 广度优先搜索队列
q.push({1, 1}); // 起点入队
while (!q.empty()) // 当队列不为空时循环
{
int x = q.front().first, y = q.front().second; // 取出队首坐标
q.pop(); // 出队
for (int i=0; i<4; i++) // 遍历四个方向
{
int nx = x, ny = y; // 初始化滑动终点
while (true) // 沿着当前方向滑动
{
int tx = nx + dx[i]; // 计算下一个位置x坐标
int ty = ny + dy[i]; // 计算下一个位置y坐标
if (tx<1 || tx>h || ty<1 || ty>w) break; // 超出边界则停止
if (mp.count({tx, ty})) break; // 遇到障碍物则停止
nx = tx, ny = ty; // 更新滑动位置
}
if (dist[nx][ny]==0x3f3f3f3f) // 如果目标位置未访问过
{
dist[nx][ny] = dist[x][y] + 1; // 更新距离
q.push({nx, ny}); // 目标位置入队
}
}
}
}
int main() // 主函数
{
cin >> h >> w >> n; // 输入网格尺寸和障碍物数量
for (int i=1; i<=n; i++) // 读取所有障碍物
{
int r, c; // 障碍物行坐标r,列坐标c
cin >> r >> c; // 输入障碍物坐标
mp[{r, c}] = 1; // 在障碍物映射表中标记
}
bfs(); // 执行广度优先搜索
if (dist[h][w]==0x3f3f3f3f) cout << -1 << endl; // 如果终点不可达输出-1
else cout << dist[h][w] << endl; // 否则输出最短距离
return 0; // 程序正常结束
}
【运行结果】
3 3 1
2 2
2
浙公网安备 33010602011771号