1. 程式人生 > 其它 >AtCoder Beginner Contest 241 F - Skate(bfs、STL)

AtCoder Beginner Contest 241 F - Skate(bfs、STL)

F - Skate

題目大意:

每次移動,沿著一個方向一直運動,直到遇到障礙物才停下,問從起點到終點的移動次數。

思路:

由於之前玩過類似的遊戲,題意比較好理解。

考慮每個位置上我們有哪些選擇,按照題意,我們只有上下左右四個方向,並且沿著這個方向需要碰到障礙物,否則就會出界,注意碰到障礙物就會停止,並不會立即穿過這個障礙物,這樣看的話,還是相當於四個方向 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;
}