質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1752閲覧

[AOJ]「IPT1_11_B サイコロIII」の同一サイコロを判定処理がわかりません

smile_20200722

総合スコア11

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2021/06/15 10:24

編集2021/06/17 01:17

前提・実現したいこと

AIZU ONLINE JUDGEの「IPT1_11_C サイコロIII」の問題で、同一のサイコロを判定する処理をどのように書けばいいかわかりません。
2つの同一のサイコロを判定する処理は、以下のソースコードのis_same_dice関数です。

問題文については、お手数をかけしますが、リンク先をご覧ください。
リンク先にありますSample Input1と2は期待通りの出力が得られます。
https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_C

どうぞよろしくお願いいたします。

発生している問題・エラーメッセージ

以下のソースコードを投稿すると、テストケース6でYESの出力が得られません。
テストケース6の入力値

10 20 20 40 50 50 50 10 20 20 40 50

該当のソースコード

C++

1#include <bits/stdc++.h> 2using namespace std; 3 4class Dice { 5 public: 6 Dice(int number[]); 7 void print_status(); 8 int get_status(int number); 9 void toss(char direction); 10 bool is_same_dice(Dice d); 11 12 private: 13 int dice[6]; 14}; 15 16Dice::Dice(int n[]) { 17 for(int i = 0; i < 6; i++) { 18 dice[i] = n[i]; 19 } 20} 21 22void Dice::print_status() { 23 for(int i = 0; i < 6; i++) { 24 cout << dice[i] << " "; 25 } 26 cout << endl; 27} 28 29int Dice::get_status(int number) { return dice[number]; } 30 31void Dice::toss(char direction) { 32 int tmp; 33 switch(direction) { 34 case 'N': 35 tmp = dice[0]; 36 dice[0] = dice[1]; 37 dice[1] = dice[5]; 38 dice[5] = dice[4]; 39 dice[4] = tmp; 40 case 'S': 41 tmp = dice[0]; 42 dice[0] = dice[4]; 43 dice[4] = dice[5]; 44 dice[5] = dice[1]; 45 dice[1] = tmp; 46 case 'E': 47 tmp = dice[0]; 48 dice[0] = dice[3]; 49 dice[3] = dice[5]; 50 dice[5] = dice[2]; 51 dice[2] = tmp; 52 case 'W': 53 tmp = dice[0]; 54 dice[0] = dice[2]; 55 dice[2] = dice[5]; 56 dice[5] = dice[3]; 57 dice[3] = tmp; 58 } 59} 60 61bool Dice::is_same_dice(Dice d) { 62 for(int i = 0; i < 6; i++) { 63 if(i < 4) { 64 toss('S'); 65 } else if(i == 4) { 66 toss('E'); 67 } else { 68 toss('W'); 69 toss('W'); 70 } 71 72 if(get_status(0) == d.get_status(0) && 73 get_status(1) == d.get_status(1) && 74 get_status(2) == d.get_status(2)) { 75 return true; 76 } 77 } 78 return false; 79} 80 81int main() { 82 int dice_table[2][6]; 83 84 for(int i = 0; i < 2; i++) { 85 for(int j = 0; j < 6; j++) { 86 cin >> dice_table[i][j]; 87 } 88 } 89 90 Dice d1(dice_table[0]), d2(dice_table[1]); 91 92 if(d1.is_same_dice(d2)) { 93 cout << "Yes" << endl; 94 } else { 95 cout << "No" << endl; 96 } 97 return 0; 98} 99

追加(2021/06/16)

C++

1bool Dice::is_same(Dice d) { 2 for(int i = 0; i < 6; i++) { 3 if(dice[i] != d.get_status(i)) { 4 return false; 5 } 6 } 7 return true; 8} 9 10bool Dice::is_same_dice(Dice d) { 11 for(int i = 0; i < 6; i++) { 12 if(i < 4) { 13 toss('S'); 14 } else if(i == 4) { 15 toss('E'); 16 } else { 17 toss('W'); 18 toss('W'); 19 } 20 21 for(int j = 0; j < 4; j++) { 22 if (j == 1) { 23 toss('E'); 24 } else if(j < 4) { 25 toss('S'); 26 } 27 if (is_same(d)) { 28 return true; 29 } 30 } 31 // toss('S'); 32 toss('W'); 33 } 34 return false; 35}

テストケース11の入力値
期待通りのYesの出力が得られない。

1 2 3 4 5 6 5 3 6 1 4 2

追加(2021/06/17)

側面のみを回転させる関数right_rotationを書いてみましたが、不合格になってしまっています。

C++

1bool Dice::is_same_dice(Dice d) { 2 for(int i = 0; i < 6; i++) { 3 if(i < 4) { 4 toss('S'); 5 } else if(i == 4) { 6 toss('E'); 7 } else { 8 toss('W'); 9 toss('W'); 10 } 11 12 for(int j = 0; j < 4; j++) { 13 right_rotation(); 14 if(is_same(d)) { 15 return true; 16 } 17 } 18 } 19 return false; 20} 21 22void Dice::right_rotation() { 23 int tmp = dice[1]; 24 dice[1] = dice[2]; 25 dice[2] = dice[4]; 26 dice[4] = dice[3]; 27 dice[3] = tmp; 28}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

同一のサイコロを判定する処理をどのように書けばいいか

私は頭が良くないので,同一判定方法を以下のように考えます.

  • 方針:一方のダイスの姿勢を固定し,他方のダイスの姿勢を変えていく.ある姿勢において6つの面の全ての値が等しければ同一である.
  • 探索回数:ダイスの姿勢のパターン数.ある面を上にした姿勢は4パターンあるので,単純に考えて 6*4=24 パターン調べるんじゃないだろうか?

…という話と,示された Dice::is_same_dice とを見比べてみると,

  • 3面の値しか等値のチェックをしていないように見える
  • 6パターンの姿勢しか調べていないように見える

というところが不思議です.
おそらく私の考えよりも効率的な何らかの話を実装しているのではないかと思うのですが,

2つの同一のサイコロを判定する処理は、以下のソースコードのis_same_dice関数です

とだけ言われても,どのようなアルゴリズムで判定をするつもりのコードなのかが不明です.
(まともに動かないコードならば,コードから読み取るのも限界があります)

投稿2021/06/15 11:06

fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

smile_20200722

2021/06/15 16:08

fanaさん、コメントありがとうございます。 is_same_dice関数の3面しかチェックしてないのは、私の理解不足です。 一つのサイコロの姿勢を固定し、6面を上にもってきて、その値と隣り合う2面を比較すれば同一だと考えていました。 探索回数の「ある面を上にした姿勢は4パターン」とはどういう意味でしょうか?
fana

2021/06/16 01:06 編集

問題文を見る限り,入力値には何の仮定も与えられていない: ある面の値とその裏側の面の値との間に何かの関連性があるわけでもなく, また,2つのダイスの面の値として「同一の6つの値の組」が与えられるという話でもない …ようですから,単純に考えれば6個の面の値は全て比較する必要があると見えます. > 「ある面を上にした姿勢は4パターン」 ある面を上に向けてダイスを置いたとき,ダイスの6面を{上面と底面と「側面が4こ」}と呼べますよね. この4つの側面のうちどれがどっち方向に向いているか(例えば,どれが"手前側"に向いているか)? という点で,姿勢にパターンがありますよね. 鉛直軸を回転軸としてくるくる回せるので.
smile_20200722

2021/06/16 11:42

fanaさん、コメントありがとうございます。 追加でソースコードを掲載しましたので、見ていただけると助かります。 側面の4つについて判定することはわかりましたが、その4つをどのように記述すればいいかわかりません。 側面の4つについて自分なりの解釈でis_same_dice関数を書いてみましたが、テストケース11で期待通りの出力が得られませんでした。 やってることは、それぞれの上を軸とした6面に対して、側面に向きを変えて各4面を上にし、サイコロの各面が一致しているかを判定し、サイコロを元の向きに戻しています。 これだとテストケース11まで通ります。 ただ、私の考えだとコメントアウトしている向きに直したいのですが、これですと一つもテストケースが通らなくなってしまいます。 根本的に考えた方が間違えているでしょうか?
fana

2021/06/17 01:11

考えている通りに動いているのかを確認してください. (その作業を他者に投げるべきではないです) 私の考えで言えば,6*4 = 24 パターンの姿勢をチェックすることになりますが, もしも私がそれを実装して「なんか動作しない」という状態になったとしたら, まずは 24パターンの回転姿勢の状態を全てどこかに出力し, 各姿勢での要素数6個の配列のあるべき内容を紙上で書き出したものと比較します.
smile_20200722

2021/06/17 04:12

fanaさん、コメントありがとうございます。 サイコロの状態を出力して確認しました。 6面の姿勢で重要なtoss関数に誤りがありました。 switch文の各項目にbreakを書いておらず、一部姿勢がもとのままになってしまっていました。
fana

2021/06/17 04:25

解決したようでなによりです. --- 「デバッグしてください」という話が出ると {無言で退会する,どこかにマルチポストする,逆ギレする}等々,とにかくまともな反応が得られないのが平常運転なteratailにおいて, 「しました/そして問題点がわかりました」という真っ当な反応が返された稀有な例ですね.
fana

2021/06/17 04:41 編集

それはそれとして,効率の面で考えれば 「一方のダイスAの姿勢を固定して,他方のダイスBの姿勢を色々変えてチェックする」とき, たとえば Aの上面の値が10であるとしたら,チェックすべきBの姿勢とは,上面の値が10である姿勢のみです. なので, 「Bの6面の値を見て,値が10である面についてのみ,(それを上面とした姿勢を)チェックする」というような形の記述にできれば,不要な姿勢の計算をせずに済むかもしれません. また,上面の値を合わせてから4つの回転姿勢を試す前に底面の値の一致チェックを先に行えば,4つの姿勢を試す前に棄却できます. そうすると,細かい話ですが,4つの回転姿勢においてチェックする値は4箇所で済む(上下の面はもうチェック済みなので)とかいう形になりますね. 回答内に書いた > 私の考えよりも効率的な何らかの話を実装しているのではないか というのは,「そういったような効率の最適化を施した結果のコードなのかも」という話でした.
smile_20200722

2021/06/18 15:23

fanaさん、コメントありがとうございます。 正直、動作するコードを書くことがままなりませんので、なかなか最適化まで頭が回ってない状況です。 効率の面のご指摘もありがとうございます。 それらを踏まえた書き方にも挑戦してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問