朝日新聞2006年1月20日のパズル横丁問題

問題

太郎,次郎がしりとりをする。太郎,次郎が知っている言葉は以下の15単語のみとする。

あい いか いし
いぬ いま えと
かき きく くち
しか ちえ とし
ぬか まめ めし

太郎が「あい」で始めたしりとりで次郎が必勝するためには次になんと言えば良いか?

解答への道(ヒント)

しりとりだけど「ん」が入っていない。「ん」を言って負けることは無い。次に言える言葉が無くなるか全部の単語を使い果たしたら負け。

1515というアホな探索は流石にしない。15の単語全てについて,次に言える単語を求めておく。

それは木構造(論理上は)になるのでそれを探索する。

プログラムは以下のようになる。

cstring word[] = { "あい",      // 太郎と次郎が知っている全ての単語
                   "いか",
                   "いし",
                   "いぬ",
                   "いま",
                   "えと",
                   "かき",
                   "きく",
                   "くち",
                   "しか",
                   "ちえ",
                   "とし",
                   "ぬか",
                   "まめ",
                   "めし"};
const int num_word = sizeof(word) / sizeof(word[0]); // 単語数
int nextword[num_word][num_word]; // しりとり出来る単語の並び
int num_nextword[num_word];     // しりとり出来る単語の数
int num_win[num_word];          // 次郎の2番目の単語での勝ち数
int num_loss[num_word];         // 次郎の2番目の単語での負け数
YesNo word_used[num_word];      // 単語は既に使われたか?
int find_word[num_word];        // 太郎・次郎が言った単語
void find_next( int lvl, int ab, int preword) // 次の単語を言う
{
  // lvl        :次の単語
  // ab         :==0:次は太郎
  //             !=0:次は次郎
  // preword    :前の人が言った単語
  // 次の単語を考える。
  // あれば次の単語を find_next, 無ければ負けを記録
}

int main( int argc, cstring argv[])
{
  // しりとりできる単語の繋がりを求める
  for( int i=0; i< num_word; i++) {
    jap         chr_last = lastjap(word[i]); // 前の単語の最後の文字
    int         n = 0;
    for( int j=0; j< num_word; j++) { // 次の単語全てを調べる
      if( chr_last == firstjap( word[j])) { // 前の単語と後ろの単語が繋がる
        nextword[i][n++] = j;   // 次の単語を記録しておく
      }
    }
    num_nextword[i] = n;        // word[i]に繋がる単語の数
    word_used[i] = NO;          // 単語はまだ使われていない
  }
  int lvl = 0;
  find_word[lvl] = 0;           // 「あい」から始める
  find_next( lvl+1, 1/*次は次郎の番*/, 0/*最初は「あい」と言った*/);
  // 単語と勝ち負けの数を出力してみる
  ps( "太郎 次郎 => 勝ち 負け\n");
  for( i=0; i< num_word; i++) {
    ps( "%s %s => %4d %4d", word[0], word[i], num_win[i], num_loss[i]);
    if( num_win[i] > 0 && num_loss[i] == 0) ps( " ☆\n");
    else ps( "\n");
  }
  return    0;
}

答え(☆の行)は1件出力されました。勝ち負けの数が1になっているので,しりとりとしては不安を感じたので途中デバッグ出力を入れたけど間違ってはないようだ。

 

昨年末から免許証の書き換えに行かなければと思っていて,今日ようやくそれを思い出し行ってきた。

視力検査で私のちょうど前の人が何回か言い間違いをして,「おいおい,こんな所で言い間違いかよ。誰もが見えるのしか表示されないぞ。」と思った。

私の番が来て覗いてビックリ。「よく見えない」。マズイ。慌ててメガネをかけ直しもう一度見直す。今度は少し見えるぞ。

何とかそれらしき方向を言って無事通過。

それにしてもメガネは1ヶ月ほど前に買い換えたばかりなのに。

作るとき,「これで視力は幾つになるんですか」と私が聞くと「1.5です」

あの言葉は何だったんだ。

免許証の写真を見てビックリ。痩せすぎて知らない人が写っているみたいだ。

「俺ってこんな顔かー」としみじみ眺める。

世間はライブドアショックで大騒ぎ。マスコミは手のひらを返したようにライブドア叩き。恐いねー。

解速度