paizaラーニング レベルアップ問題集 新・Bランクレベルアップメニュー JavaScript 【配列 2】立体で計算

【配列 2】立体で計算 (paizaランク B 相当)

https://paiza.jp/works/mondai/b_rank_new_level_up_problems/b_rank_new_level_up_problems__calculate_in_three_dimensions

# 考え方
三次元立体を考えた。
三次元軸の正方向を決める。
入力される値は、最初の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の４通りある。

```javascript
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の一つを固定し、平面で考える。
立方体の対角線については、上の解答例と同様。
```javascript
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行が１行目の平面二次元配列
    }
  }
}

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);
```