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

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

AtCoder ABC 309 B - Rotate (灰色, 200 点)

これ、詰まる人には詰まると思う。二次元配列の添字の扱いに習熟していないと難しい。

問題概要

 N \times N のグリッドが与えられる。各マス目には 0 か 1 の値が書かれている。

このグリッドに対して、外周を時計回りに 1 マス分回して得られるグリッドを答えよ。

考えたこと

二次元配列における各マスの添字の扱いの習熟度が十分ないと、難しく感じたのではないかと思う。なお、上から  i 行目、左から  j 列目のマスを  (i, j) と書くことにする。0-indexed で考えることにするので、たとえば左上のマスは  (0, 0) となり、右下のマスは  (N-1, N-1) となる。

この問題を解く方針はいろいろ考えられるが、ここでは、


  • 答えとなる  N \times N のグリッドを用意する
  • 答えとなるグリッドの各マス  (i, j) が、もとのグリッド  A のどのマスに対応するかを整理する

という方針で考えることにした。具体的には次のコードのようになる。

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

int main() {
    int N;
    cin >> N;
    vector<string> A(N);
    for (int i = 0; i < N; ++i) cin >> A[i];
    
    // 答えの (i, j) マスを順に調べていく
    vector<string> res(N, string(N, '0'));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i == 0 && j >= 1) {
                // (0, 1), (0, 2), ..., (0, N-1) は左からとってくる
                res[i][j] = A[i][j-1];
            } else if (i >= 1 && j == N-1) {
                // (1, N-1), (2, N-1), ..., (N-1, N-1) は上からとってくる
                res[i][j] = A[i-1][j];
            } else if (i == N-1 && j < N-1) {
                // (N-1, 0), (N-1, 1), ..., (N-1, N-2) は右からとってくる
                res[i][j] = A[i][j+1];
            } else if (i < N-1 && j == 0) {
                // (0, 0), (1, 0), ..., (N-2, 0) は下からとってくる
                res[i][j] = A[i+1][j];
            } else {
                // 外周以外はそのままとってくる
                res[i][j] = A[i][j];
            }
        }
    }
    
    // 出力
    for (int i = 0; i < N; ++i) cout << res[i] << endl;
}