朝日新聞2006年3月31日のパズル横丁問題

問題

2から7までの数字がある。これらを線で結び,全ての数字に対し,その数字と直接結ばれた数字の合計が18になるようにする。

解答への道(ヒント)

合計が18になる組み合わせは以下のようなコードで出力できる。

#include "puzutl.h"

int main( int argc, cstring argv[])
{
  int a, b, c, d, e, f;
  for( int i=0; i<= 0x3F; i++) {
    if( i&1) a = 2; else a=0;
    if( i&2) b = 3; else b=0;
    if( i&4) c = 4; else c=0;
    if( i&8) d = 5; else d=0;
    if( i&16) e = 6; else e=0;
    if( i&32) f = 7; else f=0;
    int sum = a+b+c+d+e+f;
    if( sum == 18) {
      ps( "%d %d %d %d %d %d \n", a, b, c, d, e, f);
    }
  }
  return    0;
}

結果は以下のように4通りある。

0 3 4 5 6 0 
2 0 4 5 0 7 
2 3 0 0 6 7 
0 0 0 5 6 7 

しかしこのアプローチだとここから先が結構大変。よって,このアプローチは諦める。

虱潰し方法を取ることにする。

以下のような表を考える。例えば行3,列6の数字10は,ビット10を示し,ビットがONの時,3と6を連結することを意味する。

以下の表は

2進数で 000010000111100 を意味し,図に表すと以下のようになる。

表の左下半分は右上の対称になるので右上の部分だけを虱潰す以下のようなコードになる。

int main( int argc, cstring argv[])
{
  mat[0][0] = mat[1][1] = mat[2][2] = mat[3][3] = mat[4][4] = mat[5][5] = 0;
  for( int i=0; i<= 0x7FFF; i++) {
    if( i&0x0001) mat[0][1] = mat[1][0] = 1; else mat[0][1] = mat[1][0] = 0;
    if( i&0x0002) mat[0][2] = mat[2][0] = 1; else mat[0][2] = mat[2][0] = 0;
    if( i&0x0004) mat[0][3] = mat[3][0] = 1; else mat[0][3] = mat[3][0] = 0;
    if( i&0x0008) mat[0][4] = mat[4][0] = 1; else mat[0][4] = mat[4][0] = 0;
    if( i&0x0010) mat[0][5] = mat[5][0] = 1; else mat[0][5] = mat[5][0] = 0;
    if( i&0x0020) mat[1][2] = mat[2][1] = 1; else mat[1][2] = mat[2][1] = 0;
    if( i&0x0040) mat[1][3] = mat[3][1] = 1; else mat[1][3] = mat[3][1] = 0;
    if( i&0x0080) mat[1][4] = mat[4][1] = 1; else mat[1][4] = mat[4][1] = 0;
    if( i&0x0100) mat[1][5] = mat[5][1] = 1; else mat[1][5] = mat[5][1] = 0;
    if( i&0x0200) mat[2][3] = mat[3][2] = 1; else mat[2][3] = mat[3][2] = 0;
    if( i&0x0400) mat[2][4] = mat[4][2] = 1; else mat[2][4] = mat[4][2] = 0;
    if( i&0x0800) mat[2][5] = mat[5][2] = 1; else mat[2][5] = mat[5][2] = 0;
    if( i&0x1000) mat[3][4] = mat[4][3] = 1; else mat[3][4] = mat[4][3] = 0;
    if( i&0x2000) mat[3][5] = mat[5][3] = 1; else mat[3][5] = mat[5][3] = 0;
    if( i&0x4000) mat[4][5] = mat[5][4] = 1; else mat[4][5] = mat[5][4] = 0;
    check18();
  }
  return    0;
}

check18は表の全ての横計が18になるかどうかを調べる。

答えは1件出力されました。

 

ソフトバンクから出版されていたCマガジンがとうとう休刊になりました。

この雑誌でLSI-C86を付録に付けたことがプログラマ人口の増加に貢献したのではないかと思う。

しかし,書籍を通して入手せざるを得なかった情報も,やがてMSDNに移り,最近ではインターネットになってしまった。

現在プログラミング情報は殆どインターネットから入手できる現実を前に休刊もやむなしということでしょうか。

長い間ご苦労様でした。

解速度