from AtCoder Beginner Contest 241(Sponsored by Panasonic)
F.Skate
题意
H x W 的网格,存在 n 个障碍,已知起点和终点,询问从起点走到终点需要几步。
网格大小为 1e9x1e9,存在1e5 个障碍。
移动规则如下:
从当前位置,选择上下左右的某一个方向移动,遇到障碍时才能在障碍的前一格停止。
特别的是,边界不属于障碍,即若某一方向上无障碍,无法向该方向移动。
题解
首先,我们发现,需要标记和移动的点只有障碍周围的点,因此,这道题就相当于是4n * 4n 的网格上的BFS。
这道题的点主要是在于如何找到下一步移动到达的位置。
我们可以用一个map套set(也不是非得这么存),分别存下每一行和每一列上的障碍位置,在查询下一步的时候,在当前行或列二分出下一个位置即可。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int H, W, n, sx, sy, gx, gy;
map<int, set<int>>r,c;
map<pair<int, int>, bool>vis;
struct node { int x, y, s; };
int dx[10] = { 0,0,1,-1 }, dy[10] = { 1,-1,0,0 }, df[5] = { -1,0,1 };
bool ok(int x, int y) {
if (x >= 1 && x <= H && y >= 1 && y <= W)return 1;
return 0;
}
int main() {
cin >> H >> W >> n;
cin >> sx >> sy >> gx >> gy;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
r[x].insert(y), c[y].insert(x);
}
queue<node>que;
que.push({ sx, sy, 0 });
vis[{sx, sy}] = 1;
while (!que.empty()) {
node p = que.front(); que.pop();
if (p.x == gx && p.y == gy) {
cout << p.s << "\n";
return 0;
}
auto fx = r[p.x].lower_bound(p.y), fy = c[p.y].lower_bound(p.x);
if (fx != r[p.x].end() && !vis[{p.x, * fx - 1}])que.push({ p.x,*fx - 1,p.s + 1 }), vis[{ p.x, * fx - 1}] = 1;
if (fy != c[p.y].end() && !vis[{*fy - 1, p.y}])que.push({ *fy - 1, p.y,p.s + 1 }), vis[{*fy - 1, p.y}] = 1;
if (fx != r[p.x].begin()) {
fx--;
if (!vis[{p.x, * fx + 1}])que.push({ p.x,*fx + 1,p.s + 1 }), vis[{p.x, * fx + 1}] = 1;
}
if (fy != c[p.y].begin()) {
fy--;
if (!vis[{*fy + 1, p.y}])que.push({ *fy + 1, p.y,p.s + 1 }), vis[{*fy + 1, p.y}] = 1;
}
}
cout << "-1\n";
return 0;
}