朝日新聞2006年6月9日のパズル横丁問題

問題

1から100万まえの数字の読みを辞書順に並べたとき,一番大きいのはどれか?

濁点,半濁点は無視し,小さい仮名は大きい仮名と同じ並び順とする。

解答への道(ヒント)

「読み方は普通の通りで」って問題にあるが,「普通」って難しい。

7は「しち」,「なな」?

4は「し」,「よん」?

このへんは答えに影響しないし,あまり深刻に考えないことにする。

少し考えると答えが判っちゃうので,判る直前で思考停止。プログラムを組む。

1から100万までの読みを全て作り大きいのが出現するごとに記録する。

先頭が6の数字だけを調べるなんてことはしない。全部調べるんじゃ。

for( int i=1; i<= 1000000; i++) {
  iの読みを作り,今までの読みと比較する。
  大きければiの読みを記録する。
}
一番大きな読みを出力する。

読みを作るプログラムは以下のようになる。

cstring yomi[][4] = {
  { ""        , ""              , ""              , ""},
  { "いち"    , "じゅう"        , "ひゃく"        , "いっせん"},
  { "に"      , "にじゅう"      , "にひゃく"      , "にせん"},
  { "さん"    , "さんじゅう"    , "さんびゃく"    , "さんぜん"},
  { "よん"    , "よんじゅう"    , "よんひゃく"    , "よんせん"},
  { "ご"      , "ごじゅう"      , "ごひゃく"      , "ごせん"},
  { "ろく"    , "ろくじゅう"    , "ろっぴゃく"    , "ろくせん"},
  { "なな"    , "ななじゅう"    , "ななひゃく"    , "ななせん"},
  { "はち"    , "はちじゅう"    , "はっぴゃく"    , "はっせん"},
  { "きゅう"  , "きゅうじゅう"  , "きゅうひゃく"  , "きゅうせん"},
};

void make_yomi( astring s, int val, int keta) 
{
  if( val < 0) return;
  if( keta==0) {
    //strcpy( s, "★");
    return;
  }
  if( keta< 10) {
    strcpy( s, yomi[val][0]);
  }
  else if( keta< 100) {
    // 57:ごじゅう なな
    strcpy( s, yomi[val/10][1]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%10, keta/10);
  }
  else if( keta< 1000) {
    // 857:はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/100][2]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%100, keta/10);
  }
  else if( keta< 10000) {
    // 4857:よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/1000][3]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%1000, keta/10);
  }
  else if( keta< 100000) {
    // 94857:きゅうまん よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/10000][0]);
    strcat( s, "まん");
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%10000, keta/10);
  }
  else if( keta< 1000000) {
    // 394857:さんじゅう きゅうまん よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/100000][1]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%100000, keta/10);
  }
  else if( keta< 10000000) {
    // 2394857:にひゃく さんじゅう きゅうまん よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/1000000][2]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%1000000, keta/10);
  }
  else if( keta< 100000000) {
    // 12394857:せん にひゃく さんじゅう きゅうまん よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/10000000][3]);
    //strcat( s, "◆");
    make_yomi( s+strlen(s), val%10000000, keta/10);
  }
  else if( keta< 1000000000) {
    // 612394857:ろくおく せん にひゃく さんじゅう きゅうまん よんせん はっぴゃく ごじゅう なな
    strcpy( s, yomi[val/100000000][0]);
    strcat( s, "おく");
    //strcat( s, "◆");
    int v = val%100000000;
    if( v/10000 == 0) make_yomi( s+strlen(s), v%10000, keta/100000); // 万を飛ばす,これをしないと「さんおくまん」とかになる。
    else              make_yomi( s+strlen(s), val%100000000, keta/10);
  }
}

void make_yomi( astring s, int val)
{
  make_yomi( s, val, val);
}

読みを作成後,実際には影響ないけど,問題にあるように,「ぴ」⇒「ひ」,「ぁ」⇒「あ」のように変換してから比較する。

オーメン。

読みを全て生成しているので結構時間が掛かる。

解に影響しないけど,億まで読みに変換できるようにした。

よく考えたら「いっせん」と「せん」は悩むところだな。

 

ETCを使うと料金は「さんびゃくごじゅうえんです」と声で教えてくれる。ETCを付けるとき,声のあるのと無いのをどちらにしますかと聞かれた。

声で知らせてくれなくたって構わないと思っていたけど,やはり声で教えてくれた方がありがたい。

解速度

Xeon 2.4GHz で3.125秒。