0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【マップの扱い 4】マップのナンバリング

Posted at

今回は paiza の「【マップの扱い 4】マップのナンバリング」の問題に挑戦!

マップ問題の最終問題で、今までのより解きごたえがあった!


問題概要

〇 与えられるもの

  • マップの 行数 H と 列数 W
  • ナンバリングの方向 D(1~4の整数)

〇 目的

  • マップの左上 (0,0) から順に番号を振る。
  • 番号の振り方は D の値によって異なる方向。
  • 出力として H×W の番号付きマップ を出力する。

〇 座標

  • 左上が (0,0)
  • 下方向が y の正方向、右方向が x の正方向

〇 ナンバリング方向(Dの定義)

  • D = 1 → 右上 ↗
    • 斜めに下から上へ番号を振る
  • D = 2 → 右 →
    • 行ごとに左から右へ番号を振る
  • D = 3 → 下 ↓
    • 列ごとに上から下へ番号を振る
  • D = 4 → 左下 ↙
    • 斜めに上から下へ番号を振る



入力例:

4 4 1

出力例:

1 3 6 10
2 5 9 13
4 8 12 15
7 11 14 16

↓ 図があった方がわかりやすいので、paiza のサイトを見てみて!






✅ OK例:

const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];

rl.on('line', (input) => lines.push(input));
rl.on('close', () => {
    const [H, W, D] = lines[0].split(' ').map(Number);
    
    
    // 2次元配列を用意
    const map = Array.from({ length: H }, () => Array(W).fill(0));
    
    
    let num = 1;

    if (D === 2) { 
        // 横方向 →
        for (let y = 0; y < H; y++) {
            for (let x = 0; x < W; x++) {
                map[y][x] = num++;
            }
        }
    } else if (D === 3) { 
        // 縦方向 ↓
        for (let x = 0; x < W; x++) {
            for (let y = 0; y < H; y++) {
                map[y][x] = num++;
            }
        }
    } else if (D === 1) { 
        // 斜め方向 右上 ↗
        for (let s = 0; s <= H + W - 2; s++) {
            for (let y = H - 1; y >= 0; y--) {
                let x = s - y;
                if (0 <= x && x < W) {
                    map[y][x] = num++;
                }
            }
        }
    } else if (D === 4) { 
        // 斜め方向 左下 ↙
        for (let s = 0; s <= H + W - 2; s++) {
            for (let y = 0; y < H; y++) {
                let x = s - y;
                if (0 <= x && x < W) {
                    map[y][x] = num++;
                }
            }
        }
    }

    // 出力 
    map.forEach(row => console.log(row.join(' ')));
});

〇 2次元配列の準備

  • H×W のマップを 0 で初期化

〇 番号振り用のカウンタ

  • num = 1 からスタート

D に応じた番号振り分け

  • D=2(右 →):行ごとに左から右へ
  • D=3(下 ↓):列ごとに上から下へ
  • D=1(右上 ↗):斜めのラインごとに下から上へ
    • y + x = s のマスを1つのグループとして処理
  • D=4(左下 ↙):斜めのラインごとに上から下へ
    • 同じく y + x = s のマスを処理

〇 出力

  • 2次元配列を行ごとにスペース区切りで表示




🔹 1. D = 2(右 →)

普通の「横書き」。

左上 (0,0) から始めて、右に進む。行の右端まで行ったら次の行の左端へ。

例: H=3, W=4

1   2   3   4
5   6   7   8
9  10  11  12

コードの対応部分:

for (let y = 0; y < H; y++) {
  for (let x = 0; x < W; x++) {
    grid[y][x] = num++;
  }
}




🔹 2. D = 3(下 ↓)

「縦書き」。

左上 (0,0) から始めて、下に進む。列の下端まで行ったら、次の列の上端へ。

例: H=3, W=4

1   4   7  10
2   5   8  11
3   6   9  12

コードの対応部分:

for (let x = 0; x < W; x++) {
  for (let y = 0; y < H; y++) {
    grid[y][x] = num++;
  }
}




🔹 3. D = 1(右上 ↗)

「斜め右上方向」に番号を振る。

📌 処理は、y + x が同じ値のマスは同じ斜め(↗方向の線)に並んでいることを使う。

そのとき、下側から上に進むのが D=1 の特徴。



📌 詳しく → 各マス(座標)に y+x を書いてみると:(H=3, W=4)

(0,0)=0   (0,1)=1   (0,2)=2   (0,3)=3
(1,0)=1   (1,1)=2   (1,2)=3   (1,3)=4
(2,0)=2   (2,1)=3   (2,2)=4   (2,3)=5

グループごとに見ると(s = y + x):

s=0 → {(0,0)}
s=1 → {(0,1), (1,0)}
s=2 → {(0,2), (1,1), (2,0)}
s=3 → {(0,3), (1,2), (2,1)}
s=4 → {(1,3), (2,2)}
s=5 → {(2,3)}

これが「斜めのグループ分け」になっている。



例: H=3, W=4

1   3   6  10
2   5   9  11
4   8  12  13



コードの対応部分:

for (let s = 0; s <= H + W - 2; s++) {
  for (let y = H - 1; y >= 0; y--) {  // 下から上へ
    let x = s - y;
    if (0 <= x && x < W) {
      grid[y][x] = num++;
    }
  }
}

for (let s = 0; s <= H + W - 2; s++)

  • s = y + x の「斜めのグループ番号」を表している。
  • 例えば s=2 のとき、(2,0), (1,1), (0,2) が候補になる。
  • s の範囲は 最小 = 0(左上)〜最大=(H-1)+(W-1) まで。
  • なので s <= H+W-2

👉 「今どの斜めのグループを処理しているか」を表すループ

for (let y = H - 1; y >= 0; y--)

  • D=1 は下から上に読むので、y を大きい方から小さい方へ動かす。
  • これにより (y,x) の順番が 下→上になる。

👉 「グループ内の並び順」を決めている

let x = s - y;

  • 対角線の式 s = y + x を変形して x = s - y
  • つまり「今の y に対応する x の位置」を計算。

👉 y を決めたら、その斜め上にある x が自動的に決まる

if (0 <= x && x < W)

  • x が範囲外になったらスキップ。
  • 例えば (y=2, s=0) → x=-2 になるけどこれは盤面外。

👉 盤面の範囲チェック

grid[y][x] = num++;

  • 斜めの走査順に、下から上に番号を振っていく。

💡 全体の流れ(D=1 の場合)

  • s=0(0,0)1
  • s=1(1,0)=2(0,1)=3
  • s=2(2,0)=4(1,1)=5(0,2)=6
  • … という具合に「右上 ↗」に伸びる番号付けになる。




🔹 4. D = 4(左下 ↙)

これも「斜め」だが、今度は 上から下に進む。

D=1と同じように処理。

例: H=3, W=4

1   2   4   7
3   5   8  10
6   9  11  12

コードの対応部分:

for (let s = 0; s <= H + W - 2; s++) {
  for (let y = 0; y < H; y++) {  // 上から下へ
    let x = s - y;
    if (0 <= x && x < W) {
      grid[y][x] = num++;
    }
  }
}






📝 まとめ


〇 マップは2次元配列で扱う
  • H×W の配列を用意して番号を格納する

〇 番号振りは方向 D によってループ順序を変える

  • D=2(右 →):行ごとに左から右
  • D=3(下 ↓):列ごとに上から下
  • D=1(右上 ↗):斜めのラインごとに下から上 (y + x = s)
  • D=4(左下 ↙):斜めのラインごとに上から下 (y + x = s)

〇 斜めの考え方

  • 同じ y + x の値を持つマス(座標)が斜めに並んでいるを1つのグループとして扱う
  • D=1 は下から上、D=4 は上から下に処理することで向きが変わる

〇 番号カウンタを使って順番に番号を振る

  • num = 1 からスタートして順に加算

〇 出力は行ごとにスペース区切りで表示




僕の失敗談(´;ω;`)と解決法🐈

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?