[ABC241] F - Skate

[Q] https://atcoder.jp/contests/abc241/tasks/abc241_f

やってることはシンプルだが、重たい実装になってしまった。

1. 座標圧縮したい。石の他に、石の上下左右のx,y座標も考慮すべき。N*10要素すべてで座標圧縮。
2. 石の位置をx座標基準で保管するset[x] = yと、y座標基準で保管するset[y] = xを用意。
3. BFS。lower_boundで上下左右へ移動地点を探す。


実装

// 座標圧縮
template <typename T>
ll comp(vector<T> &A) {
 map<T, ll> mp;
 for (auto p : A) mp[p] = 0;
 ll sz = 0;
 for (auto &p : mp) p.second = ++sz;
 for (auto &a : A) a = mp[a];
 return sz;
}
ll dx[] = {0, 1, 0, -1};
ll dy[] = {-1, 0, 1, 0};

----------------------------------------------------------------------
ll H, W, N;
ll sx, sy, gx, gy;

set<ll> yoko[1000010];  // yoko[h]
set<ll> tate[1000010];  // tate[x]

int main() {
 cincout();

 cin >> H >> W >> N;
 cin >> sy >> sx >> gy >> gx;
// 座標圧縮したいので、石と、上下左右のマスを要素に入れる
 vector<ll> elm;
 elm.reserve(N * 10);
 rep(i, N) {
   ll x, y;
   cin >> y >> x;
   elm.push_back(y);
   elm.push_back(x);
   rep(j, 4) {
     ll ny = y + dy[j];
     ll nx = x + dx[j];
     elm.push_back(ny);
     elm.push_back(nx);
   }
 }
 elm.push_back(sy);
 elm.push_back(sx);
 elm.push_back(gy);
 elm.push_back(gx);
 ll ret = comp(elm);

 // m,u,r,d,l*2ずつ stoneだけいれる
 rep(i, N) {
   ll ny = elm[10 * i];
   ll nx = elm[10 * i + 1];
   yoko[ny].insert(nx);
   tate[nx].insert(ny);
 }
 sy = elm[N * 10];
 sx = elm[N * 10 + 1];
 gy = elm[N * 10 + 2];
 gx = elm[N * 10 + 3];

 // bfs
 queue<pll> Q;
 map<pll, bool> seen;  // N*Nになっちゃう?
 Q.push({sy, sx});
 seen[{sy, sx}] = true;

 ll turn = -1;
 while (!Q.empty()) {
   ll qsz = Q.size();
   ++turn;
   rep(i, qsz) {
     auto &[y, x] = Q.front();
     if (y == gy && x == gx) {
       cout << turn << endl;
       return 0;
     }
     // 今いる地点から、tateの直近2か所
     {
       auto it = tate[x].upper_bound(y);
       // 下にいけるか
       if (it != tate[x].end()) {
         ll ny = *it - 1;
         if (seen.count({ny, x}) == false) {
           seen[{ny, x}] = true;
           Q.push({ny, x});
         }
       }
       // 上にいけるか
       if (it != tate[x].begin()) {
         --it;
         ll ny = *it + 1;
         if (seen.count({ny, x}) == 0) {
           seen[{ny, x}] = true;
           Q.push({ny, x});
         }
       }
     }

     // 今いる地点から、yokoの直近2か所
     {
       auto it = yoko[y].upper_bound(x);
       // 右にいけるか
       if (it != yoko[y].end()) {
         ll nx = *it - 1;
         if (seen.count({y, nx}) == 0) {
           seen[{y, nx}] = true;
           Q.push({y, nx});
         }
       }
       // 左にいけるか
       if (it != yoko[y].begin()) {
         --it;
         ll nx = *it + 1;
         if (seen.count({y, nx}) == 0) {
           seen[{y, nx}] = true;
           Q.push({y, nx});
         }
       }
     }
     Q.pop();
   }
 }
 cout << -1 << endl;
}

いいなと思ったら応援しよう!