朝日新聞2007年2月23日パズル横丁解答

プログラム実行結果は以下の通り。上の出力が再帰の結果。

max:68
(((((((50 /* 9) /* 7) /* 3) /* 2) /* 5) /* 8) /* 6) /* 4
(((((((50 /* 9) /* 7) /* 3) /* 6) /* 8) /* 5) /* 2) /* 4
(((((((50 /* 9) /* 8) /* 3) /* 2) /* 5) /* 7) /* 6) /* 4
(((((((50 /* 9) /* 8) /* 3) /* 6) /* 7) /* 5) /* 2) /* 4
max:68
(((((((50 /* 9) /* 7) /* 3) /* 2) /* 5) /* 8) /* 6) /* 4
(((((((50 /* 9) /* 7) /* 3) /* 6) /* 8) /* 5) /* 2) /* 4
(((((((50 /* 9) /* 8) /* 3) /* 2) /* 5) /* 7) /* 6) /* 4
(((((((50 /* 9) /* 8) /* 3) /* 6) /* 7) /* 5) /* 2) /* 4

プログラムのソースは以下の通り。

#include "puzutl.h"

int divro( int a, int b)          // a/bの小数点以下を四捨五入してbを掛ける
{
  int           c = a/b, d = a%b;
  if( d * 2 >= b) c++;          // 切り上げじゃなくて,四捨五入ってところがポイント
  return c*b;
}

YesNo used[10];

void caldiv( YesNo used[], int v[], set<string>& R, int V, int level, int& maxH)
{
  if( level > 8) {              // 最後まで計算した?
    if( V > maxH) {             // 最大のものが出現したら
      R.clear();                // 今までの結果をクリアして
      maxH      = V;
    }
    if( V == maxH) {            // 最大の計算結果のものを
      char    buf[128];
      sprintf( buf, "(((((((%d /* %d) /* %d) /* %d) /* %d) /* %d) /* %d) /* %d) /* %d", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
      R.insert(buf);            // 記録する
    }
    return;
  }
  for( int i=2; i< 10; i++) {   // 2〜9の全ての値を調べる
    if( used[i]) continue;      // この数は既に使用済みの
    used[i]     = YES;
    v[level]= i;
    caldiv( used, v, R, divro(V,i), level+1, maxH);
    used[i]     = NO;
  }
}

int main( int argc, cstring argv[])
{
  set<string>   R;              // 計算結果の文字列
  int           maxH = -1;      // 計算結果の最大値
  int           V = 50;         // 初期値
  if(1) {                       // 再帰で求めてみる
    int         value[10];      // 途中選択した数字
    value[0]    = V;            // 初期値
    int         maxH = -1;
    caldiv( used, value, R, value[0], 1/*level*/, maxH);
    set<string>::iterator ite;
    ps( "max:%d\n", maxH);
    for( ite=R.begin(); ite != R.end(); ite++) {
      ps( "%s\n", (*ite).c_str());
    }
    //return 0;
  }
  int           A, B, C, D, E, F, G, H;
  for( int a=2; a< 10; a++) {
    used[a] = YES;
    A           = divro(V,a);
    for( int b=2; b< 10; b++) {
      if( used[b]) continue;
      used[b] = YES;
      B         = divro(A,b);
      for( int c=2; c< 10; c++) {
        if( used[c]) continue;
        used[c] = YES;
        C       = divro(B,c);
        for( int d=2; d< 10; d++) {
          if( used[d]) continue;
          used[d] = YES;
          D     = divro(C,d);
          for( int e=2; e< 10; e++) {
            if( used[e]) continue;
            used[e] = YES;
            E   = divro(D,e);
            for( int f=2; f< 10; f++) {
              if( used[f]) continue;
              used[f] = YES;
              F  = divro(E,f);
              for( int g=2; g< 10; g++) {
                if( used[g]) continue;
                used[g] = YES;
                G     = divro(F,g);
                for( int h=2; h< 10; h++) {
                  if( used[h]) continue;
                  used[h] = YES;
                  H     = divro(G,h);
                  if( H > maxH) { // より大きな計算結果が見つかった
                    maxH = H;
                    R.clear();  // それ以前の結果は削除する
                  }
                  if( H == maxH) { // 最大の計算結果を記録する
                    char    buf[128];
                    //sprintf( buf, "a:%d, b:%d, c:%d, d:%d, e:%d, f:%d, g:%d, h:%d", a, b, c, d, e, f, g, h);
                    sprintf( buf, "(((((((%d /* %d) /* %d) /* %d) /* %d) /* %d) /* %d) /* %d) /* %d", V, a, b, c, d, e, f, g, h);
                    R.insert(buf);
                  }
                  used[h] = NO;
                }
                used[g] = NO;
              }
              used[f] = NO;
            }
            used[e] = NO;
          }
          used[d] = NO;
        }
        used[c] = NO;
      }
      used[b] = NO;
    }
    used[a] = NO;
  }
  set<string>::iterator ite;
  ps( "max:%d\n", maxH);
  for( ite=R.begin(); ite != R.end(); ite++) {
    ps( "%s\n", (*ite).c_str());
  }
  return    0;
}