AtCoder Beginner Contest 241 F - Skate(bfs、STL)
题目大意:
每次移动,沿着一个方向一直运动,直到遇到障碍物才停下,问从起点到终点的移动次数。
思路:
由于之前玩过类似的游戏,题意比较好理解。
考虑每个位置上我们有哪些选择,按照题意,我们只有上下左右四个方向,并且沿着这个方向需要碰到障碍物,否则就会出界,注意碰到障碍物就会停止,并不会立即穿过这个障碍物,这样看的话,还是相当于四个方向 bfs 寻找最短路。
由于地图的长宽都为 1e9 我们考虑使用 map 离散化的存下障碍物。需要寻找的更新路径就在同一行或同一列,所以我们用 map<ll, set<ll>> r, c;
存下每一行(列)障碍物对应的列(行),这样在更新时就可以二分的来找出下一步的位置。
在实现上,我是把所有点移到了 0-index 上再操作,队列使用 array<int, 2>
存当前点和步数。
Code:
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
ll h, w, n;
cin >> h >> w >> n;
pair<ll, ll> st, en;
cin >> st.first >> st.second >> en.first >> en.second;
st.first--, st.second--, en.first--, en.second--; // 转成 0-index
vector<pair<ll, ll>> shit(n);
for (auto &[x, y] : shit) {
cin >> x >> y;
x--, y--;
}
map<ll, set<ll>> r, c;
map<ll, ll> dis;
for (auto [x, y] : shit) {
r[x].insert(y);
c[y].insert(x);
}
ll ans = -1;
queue<array<ll, 2>> q;
q.push({st.first * w + st.second, 0}); // 当前点,步数
while (!q.empty()) {
auto [now, d] = q.front();
q.pop();
if (dis.count(now) > 0) {
continue;
}
dis[now] = d;
if (now == en.first * w + en.second) {
ans = dis[now];
break;
}
ll nx = now / w, ny = now % w;
// 同一行
if (r.count(nx)) {
auto p = r[nx].lower_bound(ny);
if (p == r[nx].end()) {
q.push({nx * w + *prev(p) + 1, d + 1}); // 应该push shit旁边的空白点
} else if (p == r[nx].begin()) {
q.push({nx * w + *p - 1, d + 1});
} else {
q.push({nx * w + *prev(p) + 1, d + 1});
q.push({nx * w + *p - 1, d + 1});
}
}
// 同一列
if (c.count(ny)) {
auto p = c[ny].lower_bound(nx);
if (p == c[ny].end()) {
q.push({(*prev(p) + 1) * w + ny, d + 1});
} else if (p == c[ny].begin()) {
q.push({(*p - 1) * w + ny, d + 1});
} else {
q.push({(*prev(p) + 1) * w + ny, d + 1});
q.push({(*p - 1) * w + ny, d + 1});
}
}
}
cout << ans << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】