AtCoder Beginner Contest 241 补题(E)

F - Skate

题意:

\(h×w\)的地图中,有一个起点和终点,现在有\(n\)个障碍物,你现在可以选择上下左右其中一个方向进行移动,一旦选择一个方向就会一直朝着这个方向移动,遇到障碍物就会停止,进行下一步移动,否则就会掉出地图外,问到终点的最小移动次数是多少?

思路:

关键:\(stl+BFS\)
由于地图很大,但是障碍物的数量不多,所以以障碍物为关键,进行\(BFS\),每次从当前点,找到与当前同行同列的可达的障碍物,然后判断移动过去是否符合条件,点的存储用到了\(map,set\)\(stl\)

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int, int> PII;
map<PII, int> dis;
map<int, set<int> > r;
map<int, set<int> > c;
int h, w, n;
int sx, sy, ex, ey;
queue<PII> q;

void move(int x, int y, int step) {
    if (x < 1 || x > h || y < 1 || y > w) return;
    if (dis.count({x, y})) return;
    q.push({x, y});
    dis[{x, y}] = step;
}
signed main() {
    cin >> h >> w >> n;
    cin >> sx >> sy >> ex >> ey;
    for (int i = 1, x, y; i <= n; i++) {
        cin >> x >> y;
        r[x].insert(y);
        c[y].insert(x);
    }
    dis[{sx, sy}] = 0;
    q.push({sx, sy});
    
    while (!q.empty()) {
        auto t = q.front();
        q.pop();
        if (t.x == ex && t.y == ey) {
            cout << dis[{ex, ey}] << endl;
            return 0;
        }
        if (r.count(t.x)) {
            auto now = r[t.x].lower_bound(t.y);
            if (now != r[t.x].end()) {
                move(t.x, *now - 1, dis[{t.x, t.y}] + 1);
            }
            if (now != r[t.x].begin()) {
                now--;
                move(t.x, *now + 1, dis[{t.x, t.y}] + 1);
            }
        }
        if (c.count(t.y)) {
            auto now = c[t.y].lower_bound(t.x);
            if (now != c[t.y].end()) {
                move(*now - 1, t.y, dis[{t.x, t.y}] + 1);
            }
            if (now != c[t.y].begin()) {
                now--;
                move(*now + 1, t.y, dis[{t.x, t.y}] + 1);
            }
        }
    }
    puts("-1");
    return 0;
}

G 似乎是最大流,还没学,学完找时间再补

posted @ 2022-03-03 20:59  Wraith_G  阅读(102)  评论(0)    收藏  举报
// //