【配列 2】立体で計算 (paizaランク B 相当)
考え方
三次元立体を考えた。
三次元軸の正方向を決める。
入力される値は、最初のN行が、ある二次元平面になっていると考えられる。
その二次元配列が、N個ある、と考えられる。
解答例
三次元立体をイメージする。
三次元座標を、高さh,縦(奥行)i,横(横幅)jで考えた。
高さhは上に+、縦iは手前に+,横は右に+で考えた。
縦横の和は、各平面を積み重ねるイメージで求めた。
すなわち、高さhを固定し、i,j平面の縦横の和row_sum,col_sumを求めた。これを全てのhについて繰り返す。
他の平面についても同様。
斜めについては、各平面の斜めと立方体の対角線について考えた。
各平面の斜めについて、例えば、問題文の赤矢印は、hを固定し、i,j平面の中で斜めを考えた。
他の緑、黄色矢印についても同様。
立方体の対角線の青点矢印については、4つある。
hが増えるにつれて、iが増えるup,減るdown、jが増えるup,減るdownの4通りある。
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const N = Number(lines[0]);
const A = [];//高さh縦i横jの三次元配列A[h][i][j]
for (let h = 0; h < N; h++) { //高さhについて
const A_row_col = lines.slice(h * N + 1, h * N + N + 1).map(row_col => row_col.split(" ").map(Number));//縦横の二次元配列
A.push(A_row_col);
}
let ans = 0;//求める最大値
//縦横
//i,j平面
for (let h = 0; h < N; h++) {
for (let i = 0; i < N; i++) {
let row_sum = 0;//縦列
let col_sum = 0;//横列
for (let j = 0; j < N; j++) {
row_sum += A[h][i][j];
col_sum += A[h][j][i];
}
ans = Math.max(row_sum, col_sum, ans);
}
}
//j,h平面
for (let i = 0; i < N; i++) {
for (let h = 0; h < N; h++) {
let row_sum = 0;//縦列
let col_sum = 0;//横列
for (let j = 0; j < N; j++) {
row_sum += A[j][i][h];
col_sum += A[h][i][j];
}
ans = Math.max(row_sum, col_sum, ans);
}
}
//h,i平面
for (let j = 0; j < N; j++) {
for (let h = 0; h < N; h++) {
let row_sum = 0;//縦列
let col_sum = 0;//横列
for (let i = 0; i < N; i++) {
row_sum += A[h][i][j];
col_sum += A[i][h][j];
}
ans = Math.max(row_sum, col_sum, ans);
}
}
//斜め
//i,j平面 red
for (let h = 0; h < N; h++) {
let i_up_j_up = 0;
let i_down_j_up = 0;
for (let i = 0; i < N; i++) {
i_up_j_up += A[h][i][i];
i_down_j_up += A[h][N - 1 - i][i];
}
ans = Math.max(i_up_j_up, i_down_j_up, ans);
}
//j,h平面 green
for (let i = 0; i < N; i++) {
let j_up_h_jp = 0;
let j_down_h_up = 0;
for (let j = 0; j < N; j++) {
j_up_h_jp += A[j][i][j];
j_down_h_up += A[j][i][N - 1 - j];
}
ans = Math.max(j_up_h_jp, j_down_h_up, ans);
}
//h,i平面 yellow
for (let j = 0; j < N; j++) {
let h_up_i_up = 0;
let h_down_i_up = 0;
for (let h = 0; h < N; h++) {
h_up_i_up += A[h][h][j];
h_down_i_up += A[N - 1 - h][h][j];
}
ans = Math.max(h_up_i_up, h_down_i_up, ans);
}
//立方体の対角線 blue
let h_up_i_up_j_up = 0;
let h_up_i_up_j_down = 0;
let h_up_i_down_j_up = 0;
let h_up_i_down_j_down = 0;
for (let i = 0; i < N; i++) {
h_up_i_up_j_up += A[i][i][i];
h_up_i_up_j_down += A[i][i][N - 1 - i];
h_up_i_down_j_up += A[i][N - 1 - i][i];
h_up_i_down_j_down += A[i][N - 1 - i][N - 1 - i];
ans = Math.max(
h_up_i_up_j_up,
h_up_i_up_j_down,
h_up_i_down_j_up,
h_up_i_down_j_down,
ans
);
}
console.log(ans);
解答例(C++の場合参考)
入力cinとAのところ、
入力される値cinは、最初のN行が、ある二次元平面になっていると考えられる。
その二次元配列が、N個ある三次元立体と考えられる。
Aの立方体座標i,j,kはA[i][j][k]で考え、入力cinをAに配置していく。
Aの立方体座標x,y,zはA[x][y][z]で考え、
縦、横、斜め(平面内斜め、立方体の対角線)について、和を求め、最大値を求める。
平面内の縦横斜めについて考える時は、x,y,zの一つを固定し、平面で考える。
立方体の対角線については、上の解答例と同様。
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const N = Number(lines[0]);
const cin = lines.slice(1).map(line => line.split(" ").map(Number));
//縦x横y高さzの三次元配列A[x][y][z]
const A = Array(N).fill(0).map(x => x = Array(N).fill(0).map(y => y = Array(N).fill(0)));//三次元配列を初期化
for (let i = 0; i < N; i++) {
for (let j = 0; j < N; j++) {
for (let k = 0; k < N; k++) {
A[i][j][k] = cin[i * N + j][k];//最初のN行が1行目の平面二次元配列
}
}
}
let ans = 0;//求める最大値
//縦横
//x固定,yz平面
for (let x = 0; x < N; x++) {
for (let i = 0; i < N; i++) {
let row_sum = 0;
for (let j = 0; j < N; j++) {
row_sum += A[x][i][j];
}
ans = Math.max(row_sum, ans);
}
}
//y固定,zx平面
for (let y = 0; y < N; y++) {
for (let i = 0; i < N; i++) {
let row_sum = 0, col_sum = 0;
for (let j = 0; j < N; j++) {
row_sum += A[i][y][j];
col_sum += A[j][y][i];
}
ans = Math.max(row_sum, col_sum, ans);
}
}
//z固定、xy平面
for (let z = 0; z < N; z++) {
for (let i = 0; i < N; i++) {
let row_sum = 0, col_sum = 0;
for (let j = 0; j < N; j++) {
row_sum += A[i][j][z];
col_sum += A[j][i][z];
}
ans = Math.max(row_sum, col_sum, ans);
}
}
//斜め
//x固定,yz平面
for (let x = 0; x < N; x++) {
let left_right_down = 0, left_right_up = 0;
for (let i = 0; i < N; i++) {
left_right_down += A[x][i][i];
left_right_up += A[x][N - 1 - i][i];
}
ans = Math.max(left_right_down, left_right_up, ans);
}
//y固定,zx平面
for (let y = 0; y < N; y++) {
let left_right_down = 0, left_right_up = 0;
for (let i = 0; i < N; i++) {
left_right_down += A[i][y][i];
left_right_up += A[N - 1 - i][y][i];
}
ans = Math.max(left_right_down, left_right_up, ans);
}
//z固定、xy平面
for (let z = 0; z < N; z++) {
let left_right_down = 0, left_right_up = 0;
for (let i = 0; i < N; i++) {
left_right_down += A[i][i][z];
left_right_up += A[i][N - 1 - i][z];
}
ans = Math.max(left_right_down, left_right_up, ans);
}
//立方体の対角線 blue
let l_1 = 0, l_2 = 0, l_3 = 0, l_4 = 0;
for (let i = 0; i < N; i++) {
l_1 += A[i][i][i];
l_2 += A[i][N - 1 - i][N - 1 - i];
l_3 += A[i][N - 1 - i][i];
l_4 += A[i][i][N - 1 - i];
}
ans = Math.max(ans, l_1, l_2, l_3, l_4);
//出力
console.log(ans);