(2005.11.04)新聞の解答欄によれば以下の解答は間違い。正解は最初が「ある」で,以降全部「ない」ということだ。正解者は3名ということだが,星2つ問題でなく,星3つ問題として出題されていたら正解率はもっと上がっただろうに。
(2005.11.07)嘘つき問題はやはり苦手だ。やっぱり判りづらい。以下解答を抜粋する。
-----ここから-----
最初の□に「ある」そのあとの□全部に「ない」を入れる。
□が二つの場合を考えてみます。
「パズル君は「自分は「自分はうそつきで□」と言ったことが□」と言った」
という文で,パズル君が正直者の時につじつまがあい,うそつきの時に矛盾する内容になるのは,□が順に「ある」「ない」の時だけです。
うそつきの場合,「自分は「○○」と言ったことがない」というのは「○○」と言ったことになり,「」が次々にはずれ,答えにたどりつきます。
応募111通で正解率3%。
-----ここまで-----
プログラムの実行結果は以下の通り。
嘘つきは「私は嘘つきでない(偽)」と言ったことが⇒ ない⇒ ない⇒ ない⇒ ない⇒ ない⇒ ない ⇒この発言は 偽 である★ 正直者は「私は嘘つきでない(真)」と言ったことが⇒ ある⇒ ある⇒ ある⇒ ある⇒ ある⇒ ある ⇒この発言は 真 である★
正直者の行の発言が正解かな。問題文に合わせると,
「自分は
「自分は
「自分は
「自分は
「自分は
「自分は
「自分は嘘つきでない」
と言ったことがある」
と言ったことがある」
と言ったことがある」
と言ったことがある」
と言ったことがある」
と言ったことがある」
プログラムのソースは以下の通り。
#include "puzutl.h" const int N6 = 6; // 6回「ある」,「ない」を繰り返す const int N = 1<<N6; // 6回の「ある」,「ない」の組合せ YesNo logarunai[N6+10]; YesNo logtf[N6+10]; void check( YesNo man/*正直者(YES)/嘘つき(NO)*/, YesNo usotuki/*最初の「私は嘘つきで(ある/ない)*/, YesNo truefalse/*私は○○と言ったことが{ある|ない},○○の真偽*/, int cnt/*回数*/, int diffarunai/*正直者は○○が(真)なら「ある」と言い,偽なら「ない」と言う*/ /*嘘つきは○○が(真)なら「ない」と言い,偽なら「ある」と言う*/ ) { if( man != truefalse) return; if( cnt >= N6) { ps( "%sは「私は嘘つきで%s(%s)」と言ったことが",man?"正直者":"嘘つき", usotuki?"ある":"ない", logtf[0]?"真":"偽"); for( int i=0; i< N6; i++) { ps( "⇒ "); ps( "%s", logarunai[i]?"ある":"ない"); } ps( " ⇒この発言は %s である", truefalse?"真":"偽"); if( man == truefalse) ps( "★"); ps( "\n"); return; } logarunai[cnt] = diffarunai&1; logtf[cnt] = truefalse; if( man && truefalse && ((diffarunai&1)==1)) check( man, usotuki, YES, cnt+1, diffarunai>>1); // (正直者)は「(真)を言ったことが(ある)」⇒真 if( man && truefalse && ((diffarunai&1)==0)) check( man, usotuki, NO , cnt+1, diffarunai>>1); // (正直者)は「(真)を言ったことが(ない)」⇒偽 if( man && !truefalse && ((diffarunai&1)==1)) check( man, usotuki, NO , cnt+1, diffarunai>>1); // (正直者)は「(偽)を言ったことが(ある)」⇒偽 if( man && !truefalse && ((diffarunai&1)==0)) check( man, usotuki, YES, cnt+1, diffarunai>>1); // (正直者)は「(偽)を言ったことが(ない)」⇒真 if( !man && truefalse && ((diffarunai&1)==1)) check( man, usotuki, NO, cnt+1, diffarunai>>1); // (嘘つき)は「(真)を言ったことが(ある)」⇒偽 if( !man && truefalse && ((diffarunai&1)==0)) check( man, usotuki, YES, cnt+1, diffarunai>>1); // (嘘つき)は「(真)を言ったことが(ない)」⇒真 if( !man && !truefalse && ((diffarunai&1)==1)) check( man, usotuki, YES, cnt+1, diffarunai>>1); // (嘘つき)は「(偽)を言ったことが(ある)」⇒真 if( !man && !truefalse && ((diffarunai&1)==0)) check( man, usotuki, NO, cnt+1, diffarunai>>1); // (嘘つき)は「(偽)を言ったことが(ない)」⇒偽 } int main( int argc, cstring argv[]) { for( int i=0; i< N; i++) { // ある,ないの組合せ,下位ビットからある(1),ない(0)を取り出す check( YES/*正直者が*/, YES/*「私は嘘つきで(ある)」*/, NO /*は(偽)*/, 0/*6回*/, i/*と言ったことが「ある(ON)/なし(OFF)」の組合せ*/); check( NO /*嘘つきが*/, YES/*「私は嘘つきで(ある)」*/, YES/*は(真)*/, 0/*6回*/, i/*と言ったことが「ある(ON)/なし(OFF)」の組合せ*/); check( YES/*正直者が*/, NO /*「私は嘘つきで(ない)」*/, YES/*は(真)*/, 0/*6回*/, i/*と言ったことが「ある(ON)/なし(OFF)」の組合せ*/); check( NO /*嘘つきが*/, NO /*「私は嘘つきで(ない)」*/, NO /*は(偽)*/, 0/*6回*/, i/*と言ったことが「ある(ON)/なし(OFF)」の組合せ*/); } return 0; }