(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;
}