けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 364 B - Grid Walk (6Q, 灰色, 200 点)

二次元グリッド上で、マス  (x, y) の上下左右のマスがなんであるかを学ぶ問題!

問題概要

 H \times W の二次元グリッドが与えられる。グリッドの各マスは '.'(通路)または '#'(壁)である。

はじめ高橋くんはマス  (S_{x}, S_{y}) にいる。これから高橋君に  N 回の命令がくだる(サイズ  N の文字列  X として与えられる)。

  • 文字 'U' ならば、上のマスに移動する(壁またはグリッド外の場合は移動しない)
  • 文字 'D' ならば、下のマスに移動する(壁またはグリッド外の場合は移動しない)
  • 文字 'L' ならば、左のマスに移動する(壁またはグリッド外の場合は移動しない)
  • 文字 'R' ならば、右のマスに移動する(壁またはグリッド外の場合は移動しない)

最終的に高橋くんのいるマスを答えよ。

制約

  •  1 \le H, W, N \le 50

考えたこと

グリッドにおいて、上から  x 行目、左から  y 列目のマスを  (x, y) としましょう(一番上の行を 0 行目、一番左の列を 0 列目とします)。このとき、


  • マス  (x, y) の上のマスは、 (x-1, y)
  • マス  (x, y) の下のマスは、 (x+1, y)
  • マス  (x, y) の左のマスは、 (x, y-1)
  • マス  (x, y) の右のマスは、 (x, y+1)

このことを利用してシミュレーションしましょう。ただし、

  • グリッドの外部に出てしまうような移動である場合は、スキップしましょう
  • 移動先のマスが壁マスである場合も、スキップしましょう

以上の処理を実装すると、次のコードのようになります。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    int H, W, x, y;
    cin >> H >> W >> x >> y;
    --x, --y;  // 0-indexed にする
    vector<string> C(H);
    for (int i = 0; i < H; i++) cin >> C[i];
    string X;
    cin >> X;


    for (auto c : X) {
        int x2 = x, y2 = y;
        if (c == 'U') --x2;
        else if (c == 'D') ++x2;
        else if (c == 'L') --y2;
        else ++y2;

        // 場外の場合はスキップ
        if (x2 < 0 || x2 >= H || y2 < 0 || y2 >= W || C[x2][y2] == '#') continue;

        // 壁マスの場合はスキップ
        if (C[x2][y2] == '#') continue;

        // 移動成立の場合は現在マスを更新
        x = x2, y = y2;
    }
    cout << x+1 << " " << y+1 << endl;
}