AtCoder Beginner Contest 241 F - Skate(bfs、STL)
阿新 • • 發佈:2022-03-01
題目大意:
每次移動,沿著一個方向一直運動,直到遇到障礙物才停下,問從起點到終點的移動次數。
思路:
由於之前玩過類似的遊戲,題意比較好理解。
考慮每個位置上我們有哪些選擇,按照題意,我們只有上下左右四個方向,並且沿著這個方向需要碰到障礙物,否則就會出界,注意碰到障礙物就會停止,並不會立即穿過這個障礙物,這樣看的話,還是相當於四個方向 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; }