頭の体操


お題

【HackerRank】Forming a Magic Square

  • Magic Squareを作りたい(日本語で言うと魔方陣というやつ)

  • インプットとして3 × 3の行列が与えられる

  • インプットの行列を3 × 3の魔方陣として成立させるために必要なコストの最小値を返り値とする関数formingMagicSquareを完成させる

  • コストは、|各マスの値 - 変更後の値|の合計

前提

  • 言語はRust(勉強中)で挑戦

  • 3×3の魔方陣として成立する形は、どうやら以下の形(&その対称形)しかないらしい

    • 8 3 4

    • 1 5 9

    • 6 7 2

作戦

  • すべての完成形におけるコストを求め、最小値を返す

  • 完成形は対称パターンで8通り(参考にさせていただいたサイト:https://mathlog.info/articles/3242)

    1. あるパターンそのまま

    2. 左右反転

    3. 右に90°回転

    4. 右に180°回転

    5. 右に270°回転

    6. 左右反転して右に90°回転

    7. 左右反転して右に180°回転

    8. 左右反転して右に270°回転

  • つまり、行列を左右反転させる関数と右に90°回転させる関数を用意すれば、スタティックに定義するのは1パターンだけで済みそう

とりあえず作ってみた

いろいろと前提に甘えている表現や、もうちょいスマートにかけそうなところはありつつもとりあえず作ってみた。
magic_pattern1はなんでもOK。
1を基準に作戦の項で上げた全パターンを網羅する

use std::fs::File;
use std::io::{self, BufRead, Write};
use std::{env, vec};

/*
 * Complete the 'formingMagicSquare' function below.
 *
 * The function is expected to return an INTEGER.
 * The function accepts 2D_INTEGER_ARRAY s as parameter.
 */

fn forming_magic_square(s: &[Vec<i32>]) -> i32 {
    let mut cost: Vec<i32> = Vec::new();
    let magic_pattern1 = vec![vec![8, 3, 4], vec![1, 5, 9], vec![6, 7, 2]];
    let magic_pattern2 = left_right_flip(&magic_pattern1);
    let magic_pattern3 = rotate_clockwise(&magic_pattern1);
    let magic_pattern4 = rotate_clockwise(&magic_pattern3);
    let magic_pattern5 = rotate_clockwise(&magic_pattern4);
    let magic_pattern6 = rotate_clockwise(&magic_pattern2);
    let magic_pattern7 = rotate_clockwise(&magic_pattern6);
    let magic_pattern8 = rotate_clockwise(&magic_pattern7);

    let magic_pattern = vec![
        magic_pattern1,
        magic_pattern2,
        magic_pattern3,
        magic_pattern4,
        magic_pattern5,
        magic_pattern6,
        magic_pattern7,
        magic_pattern8,
    ];

    for p in magic_pattern {
        let mut cost_this_pattern = 0;
        for i in 0..3 {
            for j in 0..3 {
                cost_this_pattern += (s[i][j] - p[i][j]).abs();
                // dbg!(s[i][j]);
                // dbg!(p[i][j]);
            }
        }
        cost.push(cost_this_pattern);
    }
    let min_cost: i32 = match cost.iter().min() {
        Some(n) => *n,
        None => unreachable!(),
    };
    min_cost
}

fn rotate_clockwise(s: &[Vec<i32>]) -> Vec<Vec<i32>> {
    let rotated = vec![
        vec![s[2][0], s[1][0], s[0][0]],
        vec![s[2][1], s[1][1], s[0][1]],
        vec![s[2][2], s[1][2], s[0][2]],
    ];
    rotated
}
fn left_right_flip(s: &[Vec<i32>]) -> Vec<Vec<i32>> {
    let fliped = vec![
        vec![s[0][2], s[0][1], s[0][0]],
        vec![s[1][2], s[1][1], s[1][0]],
        vec![s[2][2], s[2][1], s[2][0]],
    ];
    fliped
}

fn main() {
    let stdin = io::stdin();
    let mut stdin_iterator = stdin.lock().lines();

    let mut fptr = File::create(env::var("OUTPUT_PATH").unwrap()).unwrap();

    let mut s: Vec<Vec<i32>> = Vec::with_capacity(3_usize);

    for i in 0..3_usize {
        s.push(Vec::with_capacity(3_usize));

        s[i] = stdin_iterator
            .next()
            .unwrap()
            .unwrap()
            .trim_end()
            .split(' ')
            .map(|s| s.to_string().parse::<i32>().unwrap())
            .collect();
    }

    let result = forming_magic_square(&s);

    writeln!(&mut fptr, "{}", result).ok();
}

結果

一応すべてのテストケースをクリアした


この記事が気に入ったらサポートをしてみませんか?