今回は paiza の「【配列 2】立体で計算」の問題に挑戦!
三次元配列の扱いに初挑戦!
問題概要
〇 入力
-
N×N×Nの立方体配列が与えられる
入力形式は 平面ごとに1行ずつのN×N行列がN層分並んだ形式 -
例えば N = 2 の場合:
1 2 ← 1層目
2 3
3 2 ← 2層目
2 1
〇 出力
-
N要素からなる縦列・横列・斜め列の和の最大値を出力 - 「縦列・横列・斜め列」の意味:
- 縦列(x方向、y方向、z方向いずれも含む)
- 例:同じ層の横一列、縦一列、層をまたぐ列
- 斜め列
- 平面内の斜め
- XY平面の左上→右下、右上→左下
- YZ平面や ZX平面も同様
- 立体の空間対角線
- 立方体の一番手前の角から一番奥の角までの対角線
- 平面内の斜め
- 縦列(x方向、y方向、z方向いずれも含む)
〇 条件・制約
- 各列の長さは
N - 立方体の全ての行・列・平面斜め・空間対角線を考慮する
-
Nの最大値が50なので、単純な三重ループでも十分計算可能
入力例:
2 // N
1 2
2 3
3 2
2 1
出力例:
6
✅ OK例:
const fs = require("fs");
// 入力をスペース区切りでまとめて数値配列に変換
const input = fs.readFileSync(0, "utf8").trim().split(/\s+/).map(Number);
let idx = 0;
const N = input[idx++]; // 立方体の一辺の長さ
// cube[z][y][x] として 3次元配列を初期化
const cube = Array.from({ length: N }, () =>
Array.from({ length: N }, () => Array(N).fill(0))
);
// --- 入力値を cube[z][y][x] に格納 ---
for (let z = 0; z < N; z++) {
for (let y = 0; y < N; y++) {
for (let x = 0; x < N; x++) {
cube[z][y][x] = input[idx++]; // 1つずつ取り出して代入
}
}
}
let maxSum = -Infinity; // 最大値の初期化
// -----------------------------
// 1. 各行 (x方向) の合計
// -----------------------------
for (let z = 0; z < N; z++) {
for (let y = 0; y < N; y++) {
let sum = 0;
for (let x = 0; x < N; x++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
// -----------------------------
// 2. 各列 (y方向) の合計
// -----------------------------
for (let z = 0; z < N; z++) {
for (let x = 0; x < N; x++) {
let sum = 0;
for (let y = 0; y < N; y++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
// -----------------------------
// 3. 縦方向 (z方向) の合計
// -----------------------------
for (let y = 0; y < N; y++) {
for (let x = 0; x < N; x++) {
let sum = 0;
for (let z = 0; z < N; z++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
// -----------------------------
// 4. 各平面の対角線
// -----------------------------
// (a) XY平面ごとに対角線
for (let z = 0; z < N; z++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[z][i][i]; // 左上→右下
d2 += cube[z][i][N - 1 - i]; // 右上→左下
}
maxSum = Math.max(maxSum, d1, d2);
}
// (b) YZ平面ごとに対角線
for (let x = 0; x < N; x++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[i][i][x]; // 前上→後下
d2 += cube[N - 1 - i][i][x]; // 前下→後上
}
maxSum = Math.max(maxSum, d1, d2);
}
// (c) ZX平面ごとに対角線
for (let y = 0; y < N; y++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[i][y][i]; // 左奥→右手前
d2 += cube[N - 1 - i][y][i]; // 右奥→左手前
}
maxSum = Math.max(maxSum, d1, d2);
}
// -----------------------------
// 5. 立体の空間対角線 (大対角線)
// -----------------------------
let diag1 = 0, diag2 = 0, diag3 = 0, diag4 = 0;
for (let i = 0; i < N; i++) {
diag1 += cube[i][i][i]; // (0,0,0) → (N-1,N-1,N-1)
diag2 += cube[i][i][N - 1 - i]; // (0,0,N-1) → (N-1,N-1,0)
diag3 += cube[i][N - 1 - i][i]; // (0,N-1,0) → (N-1,0,N-1)
diag4 += cube[i][N - 1 - i][N - 1 - i]; // (0,N-1,N-1) → (N-1,0,0)
}
maxSum = Math.max(maxSum, diag1, diag2, diag3, diag4);
// -----------------------------
// 出力
// -----------------------------
console.log(maxSum);
1️⃣ 入力の取得と立方体の初期化
const fs = require("fs");
const input = fs.readFileSync(0, "utf8").trim().split(/\s+/).map(Number);
let idx = 0;
const N = input[idx++]; // 立方体の一辺の長さ
// cube[z][y][x] として 3次元配列を初期化
const cube = Array.from({ length: N }, () =>
Array.from({ length: N }, () => Array(N).fill(0))
);
ポイント
-
Nは立方体の1辺の長さ。例えば N=2 なら 2×2×2 の立方体。 -
cube[z][y][x]という 3次元配列 を使って立方体を表現。- z軸:前→後
- y軸:上→下
- x軸:左→右
- このとき
cube[0][0][0]が立方体の「左上前端」、cube[N-1][N-1][N-1]が「右下後端」に対応。
2️⃣ 入力値を立方体に格納
for (let z = 0; z < N; z++) {
for (let y = 0; y < N; y++) {
for (let x = 0; x < N; x++) {
cube[z][y][x] = input[idx++]; // 1つずつ取り出して代入
}
}
}
ポイント
- 入力は1行ずつ
N×Nの平面が並んでいるイメージ。 - 外側のループ
zが前→後の層を移動。 - 真ん中のループ
yが上から下の行を移動。 - 内側のループ
xが行内の左から右の要素を取り出す。 - 結果として
cube[z][y][x]に立方体の全データが格納される。
3️⃣ 最大値を求めるための変数初期化
let maxSum = -Infinity; // 最大値の初期化
すべての「縦・横・斜めの列の合計」を調べ、最終的にここに最大値を格納する。
4️⃣ 各行 (x方向) の合計
for (let z = 0; z < N; z++) {
for (let y = 0; y < N; y++) {
let sum = 0;
for (let x = 0; x < N; x++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
ポイント
- XY平面の「横一列」の合計を計算
- イメージ:
[x][y] ← 水平方向の行
z = 前→後の層ごとに処理
- 各行の合計を maxSum と比較して最大値を更新。
5️⃣ 各列 (y方向) の合計
for (let z = 0; z < N; z++) {
for (let x = 0; x < N; x++) {
let sum = 0;
for (let y = 0; y < N; y++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
ポイント
- XY平面の「縦一列」の合計を計算
- イメージ:
[x][y] ← 縦方向の列
z = 前→後の層ごとに処理
6️⃣ 縦方向 (z方向) の合計
for (let y = 0; y < N; y++) {
for (let x = 0; x < N; x++) {
let sum = 0;
for (let z = 0; z < N; z++) sum += cube[z][y][x];
maxSum = Math.max(maxSum, sum);
}
}
ポイント
- X-Y平面で固定された位置の列を 前→後方向(z方向) に合計
- これで立方体の「縦の列」をすべて計算できる
7️⃣ 各平面の対角線
(a) XY平面
for (let z = 0; z < N; z++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[z][i][i]; // 左上→右下
d2 += cube[z][i][N - 1 - i]; // 右上→左下
}
maxSum = Math.max(maxSum, d1, d2);
}
- XY平面ごとに 平面対角線 を計算
-
d1: 左上 → 右下 -
d2: 右上 → 左下
(b) YZ平面
for (let x = 0; x < N; x++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[i][i][x]; // 前上→後下
d2 += cube[N - 1 - i][i][x]; // 前下→後上
}
maxSum = Math.max(maxSum, d1, d2);
}
- YZ平面ごとに 縦方向と奥行きの斜め を計算
(c) ZX平面
for (let y = 0; y < N; y++) {
let d1 = 0, d2 = 0;
for (let i = 0; i < N; i++) {
d1 += cube[i][y][i]; // 左奥→右手前
d2 += cube[N - 1 - i][y][i]; // 右奥→左手前
}
maxSum = Math.max(maxSum, d1, d2);
}
- ZX平面ごとに 奥行きと横方向の斜め を計算
8️⃣ 空間対角線 (立体の大対角線)
let diag1 = 0, diag2 = 0, diag3 = 0, diag4 = 0;
for (let i = 0; i < N; i++) {
diag1 += cube[i][i][i]; // 左上前 → 右下後
diag2 += cube[i][i][N - 1 - i]; // 右上前 → 左下後
diag3 += cube[i][N - 1 - i][i]; // 左下前 → 右上後
diag4 += cube[i][N - 1 - i][N - 1 - i]; // 右下前 → 左上後
}
maxSum = Math.max(maxSum, diag1, diag2, diag3, diag4);
- 立方体全体の 空間対角線 を計算
- これで「立方体を通る最大のN要素の斜め列」もカバー
9️⃣ 出力
console.log(maxSum);
- ここまでで計算した すべての縦・横・斜めの列の合計 の最大値を出力
🗒️ まとめ
-
このコードのポイントは 3次元配列を
z,y,xの順で扱うこと。 -
各平面(XY, YZ, ZX)の対角線や、立体全体の空間対角線まで網羅。
-
入力の取り込みも 1つのループで
cube[z][y][x]に格納できるので、非常に整理されている。 -
視覚的に立方体をイメージすると「どのループでどの方向の列を足しているか」が理解しやすい。