ITP1_11_D サイコロ IVをC++で解いてみた[AIZU ONLINE JUDGE]

AIZU ONLINE JUDGE

こんにちは! mnbd(@mnbbbbbd)です。

AIZU ONLINE JUDGEの「ITP1_11_D サイコロ IV」を解いてみましたので、その回答と解説をご紹介いたします。

プログラミング初心者なので、もっといい回答があるに違いありません。

あくまでも「動作はする」サンプルとしてご覧ください。

問題文

Dice I と同様の方法で、入力された整数から n 個のサイコロをつくります。これらのサイコロが、全て異なるものかどうかを判定するプログラムを作成してください。同一かどうかの判定は Dice III の方法を用います。

Input

1行目にサイコロの個数 n が与えられます。続く n 行に各サイコロの面の整数が与えられます。
各サイコロについて各面の整数が、ラベルの順番に空白区切りで1行に与えられます。

Output

入力されたサイコロがすべて異なる場合 “Yes”、同じものが1組以上含まれる場合 “No” と1行に出力してください。

Constraints

2 ≤ n ≤ 100
0 ≤ 入力されるサイコロの面の整数 ≤100

https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_D

解答

#include <bits/stdc++.h>
using namespace std;

class Dice {
  public:
    Dice();
    Dice(int number[]);
    void print_status();
    int get_status(int number);
    void toss(char direction);
    bool is_same(Dice d);
    bool is_same_dice(Dice d);
    void right_rotation();
    void set_value(int const number[6]);
    // bool is_all_same_dice(int a, int n, Dice d[]);

  private:
    int dice[6];
};

Dice::Dice() {
    for(int i = 0; i < 6; i++) {
        dice[i] = i + 1;
    }
}

Dice::Dice(int n[]) {
    for(int i = 0; i < 6; i++) {
        dice[i] = n[i];
    }
}

void Dice::print_status() {
    for(int i = 0; i < 6; i++) {
        cout << dice[i] << " ";
    }
    cout << endl;
}

int Dice::get_status(int number) { return dice[number]; }

void Dice::toss(char direction) {
    int tmp;
    switch(direction) {
    case 'N':
        tmp = dice[0];
        dice[0] = dice[1];
        dice[1] = dice[5];
        dice[5] = dice[4];
        dice[4] = tmp;
        break;
    case 'S':
        tmp = dice[0];
        dice[0] = dice[4];
        dice[4] = dice[5];
        dice[5] = dice[1];
        dice[1] = tmp;
        break;
    case 'E':
        tmp = dice[0];
        dice[0] = dice[3];
        dice[3] = dice[5];
        dice[5] = dice[2];
        dice[2] = tmp;
        break;
    case 'W':
        tmp = dice[0];
        dice[0] = dice[2];
        dice[2] = dice[5];
        dice[5] = dice[3];
        dice[3] = tmp;
        break;
    }
}

bool Dice::is_same(Dice d) {
    for(int i = 0; i < 6; i++) {
        if(dice[i] != d.get_status(i)) {
            return false;
        }
    }
    return true;
}

bool Dice::is_same_dice(Dice d) {
    for(int i = 0; i < 6; i++) {
        if(i < 4) {
            toss('S');
        } else if(i == 4) {
            toss('E');
        } else {
            toss('W');
            toss('W');
        }

        for(int j = 0; j < 4; j++) {
            right_rotation();
            if(is_same(d)) {
                return true;
            }
        }
    }
    return false;
}

void Dice::right_rotation() {
    int tmp = dice[1];
    dice[1] = dice[2];
    dice[2] = dice[4];
    dice[4] = dice[3];
    dice[3] = tmp;
}

void Dice::set_value(const int number[6]) {
    for(int i = 0; i < 6; i++) {
        dice[i] = number[i];
    }
}

int main() {
    int n;
    cin >> n;
    int dice_table[n][6];
    Dice d[n];
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < 6; j++) {
            cin >> dice_table[i][j];
        }
        d[i].set_value(dice_table[i]);
    }

    for(int i = 0; i < n; i++) {
        for(int j = i + 1; j < n; j++) {
            if(d[i].is_same_dice(d[j])) {
                cout << "No" << endl;
                return 0;
            }
        }
    }
    cout << "Yes" << endl;
}

ハマったポイント

サイコロIIIで書いた同一のサイコロを判定する関数を使えば、どのサイコロとも違うものを見つけるのは簡単でした。

ただ、配列として作ったDiceクラスの全探索にハマりました。

探索部分の合格のコードは少ないですが、もっと難しく考えてしまっていました。

100個のDiceクラスを全部違うサイコロであると判定するにはどうするか…ということですね。

感想

サイコロI~サイコロIIIで書いたコードがかなり流用できるので、問題についてのコード量は少なめでした。

難易度的にも、サイコロIIIで書いた、同一サイコロであるかどうかを判定する関数の方が難しかったように思います。

サイコロの問題に共通していますが、サイコロIからバグのないコードが書けていないとその後の問題で予想外のつまづきがありますので、想定したコードが思ったように動かない場合は、それらのコードが正確に動いているが確認したほうがいいと思います。

まとめ

AIZU ONLINE JUDGEの「ITP1_11_D サイコロ IV」を解いてみましたので、その回答と解説をご紹介いたします。

少しずつですが、プログラミングの勉強をしています。
まだ初心者ですが、よかったらつながっていただけると嬉しいです。
Twitterアカウント(@mnbbbbbd

以上です。
読んでいただきありがとうございました!

タイトルとURLをコピーしました