challenge 小町算

古典的なパズルである小町算を解くプログラムを作成してください。

小町算とは:

1□2□3□4□5□6□7□8□9=100

四角の中に、空白、+、-、×、÷のいずれかを一つ入れ、等式が成り立つようにするパズルです。

解答例:

1-2-3+4×56÷7+8×9=100

1+234×5÷6-7-89=100

参考: http://ja.wikipedia.org/wiki/%E5%B0%8F%E7%94%BA%E7%AE%97

  • evalやそれに類するものを使うか否かは自由です。
  • 割り算の際には小数点以下の切捨てが起こらないのが望ましいです。(必須ではない)
    • 切捨てが起こる場合の解答例:1÷2÷3+4+5÷6+7+89=100
  • 余裕があれば括弧を含むようにしてもいいかもしれません。

手元で20数行ほどのPythonスクリプトを書いてみたところ、101個の解答が得られました。

Posted feedbacks - Flatten

Nested Hidden

枝狩り一切無し。効率悪いと思ふ。

1
2
3
4
5
6
7
require "mathn"
(5**8).times do |i|
  s=("2".."9").inject("1") do |r,e|
    r+=["","+","-","*","/"][i%5]+e;i/=5;r
  end
  puts s if eval(s)==100
end

とりあえず投稿。括弧は使わない版。結果は101通り出てきます。

(123 - 45 - 67 + 89)
(1 * 2 - 3 + 4 - 5 + 6 + 7 + 89)
(1 + 2 * 3 - 4 - 5 + 6 + 7 + 89)
(1 - 23 + 4 * 5 + 6 + 7 + 89)
(12 - 3 - 4 + 5 - 6 + 7 + 89)
(1 + 2 + 3 * 4 - 5 - 6 + 7 + 89)
(1 - 23 - 4 + 5 * 6 + 7 + 89)
(1 * 2 / 3 + 4 * 5 / 6 + 7 + 89)
(1 / 2 * 34 - 5 + 6 - 7 + 89)
(12 + 3 + 4 + 5 - 6 - 7 + 89)
(1 * 23 - 4 + 5 - 6 - 7 + 89)
(12 / 3 + 4 * 5 - 6 - 7 + 89)
(1 - 23 - 4 - 5 + 6 * 7 + 89)
(1 * 2 - 3 + 4 + 56 / 7 + 89)
(1 + 2 * 3 - 4 + 56 / 7 + 89)
(12 + 3 + 4 - 56 / 7 + 89)
(1 * 23 - 4 - 56 / 7 + 89)
(123 + 4 - 5 + 67 - 89)
(1 + 234 * 5 / 6 - 7 - 89)
(12 + 3 * 45 + 6 * 7 - 89)
(1 + 2 * 34 - 56 + 78 + 9)
(1 + 2 + 3 - 4 + 5 + 6 + 78 + 9)
(1 * 2 * 3 - 4 + 5 + 6 + 78 + 9)
(1 * 2 + 3 * 4 + 5 - 6 + 78 + 9)
(12 + 3 * 4 - 5 - 6 + 78 + 9)
(1 * 2 * 3 * 4 - 5 - 6 + 78 + 9)
(1 * 2 - 3 + 4 * 5 - 6 + 78 + 9)
(1 + 2 + 3 * 4 * 5 / 6 + 78 + 9)
(1 + 234 * 5 * 6 / 78 + 9)
(1 + 2 * 3 + 4 + 5 + 67 + 8 + 9)
(12 + 3 - 4 + 5 + 67 + 8 + 9)
(1 - 2 + 3 * 4 + 5 + 67 + 8 + 9)
(1 - 2 - 3 + 4 * 5 + 67 + 8 + 9)
(12 * 3 - 4 * 5 + 67 + 8 + 9)
(1 / 2 / 3 * 456 + 7 + 8 + 9)
(1 + 23 - 4 + 56 + 7 + 8 + 9)
(12 + 34 + 5 * 6 + 7 + 8 + 9)
(1 - 2 - 3 + 45 + 6 * 7 + 8 + 9)
(1 * 2 + 34 + 5 + 6 * 7 + 8 + 9)
(12 + 34 - 5 + 6 * 7 + 8 + 9)
(1 * 23 + 4 + 5 + 67 - 8 + 9)
(1 + 2 + 34 - 5 + 67 - 8 + 9)
(1 * 2 + 34 + 56 + 7 - 8 + 9)
(1 + 23 * 4 + 5 - 6 + 7 - 8 + 9)
(1 + 2 + 3 * 4 * 56 / 7 - 8 + 9)
(12 + 3 * 4 + 5 + 6 + 7 * 8 + 9)
(1 * 2 * 3 * 4 + 5 + 6 + 7 * 8 + 9)
(12 - 3 + 4 * 5 + 6 + 7 * 8 + 9)
(1 - 2 - 3 + 45 - 6 + 7 * 8 + 9)
(1 * 2 + 34 + 5 - 6 + 7 * 8 + 9)
(12 + 34 - 5 - 6 + 7 * 8 + 9)
(12 - 3 - 4 + 5 * 6 + 7 * 8 + 9)
(1 * 23 + 4 + 56 / 7 * 8 + 9)
(1 * 23 * 4 - 56 / 7 / 8 + 9)
(1 + 23 - 4 + 5 + 6 + 78 - 9)
(1 * 2 + 3 + 4 * 5 + 6 + 78 - 9)
(12 * 3 - 4 + 5 - 6 + 78 - 9)
(1 * 2 + 3 - 4 + 5 * 6 + 78 - 9)
(12 / 3 / 4 + 5 * 6 + 78 - 9)
(123 + 45 - 67 + 8 - 9)
(1 + 23 * 4 - 5 + 6 + 7 + 8 - 9)
(123 - 4 - 5 - 6 - 7 + 8 - 9)
(1 - 2 + 3 * 4 * 5 + 6 * 7 + 8 - 9)
(123 + 4 * 5 - 6 * 7 + 8 - 9)
(1 + 23 * 4 + 56 / 7 + 8 - 9)
(1 * 2 + 3 + 45 + 67 - 8 - 9)
(1 * 2 * 34 + 56 - 7 - 8 - 9)
(12 / 3 + 4 * 5 * 6 - 7 - 8 - 9)
(1 - 2 + 3 + 45 + 6 + 7 * 8 - 9)
(1 - 2 + 3 * 4 * 5 - 6 + 7 * 8 - 9)
(12 / 3 + 4 * 5 * 6 * 7 / 8 - 9)
(1 + 2 + 3 - 45 + 67 + 8 * 9)
(1 * 2 * 3 - 45 + 67 + 8 * 9)
(1 - 2 - 34 + 56 + 7 + 8 * 9)
(1 / 2 * 3 / 4 * 56 + 7 + 8 * 9)
(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 * 9)
(1 * 2 * 3 + 4 + 5 + 6 + 7 + 8 * 9)
(1 + 23 - 4 - 5 + 6 + 7 + 8 * 9)
(1 - 2 * 3 + 4 * 5 + 6 + 7 + 8 * 9)
(12 * 3 - 4 - 5 - 6 + 7 + 8 * 9)
(1 + 2 * 3 + 4 * 5 - 6 + 7 + 8 * 9)
(1 - 2 * 3 - 4 + 5 * 6 + 7 + 8 * 9)
(1 + 2 - 3 * 4 + 5 * 6 + 7 + 8 * 9)
(1 + 2 * 3 * 4 * 5 / 6 + 7 + 8 * 9)
(12 + 3 * 4 + 5 + 6 - 7 + 8 * 9)
(1 * 2 * 3 * 4 + 5 + 6 - 7 + 8 * 9)
(12 - 3 + 4 * 5 + 6 - 7 + 8 * 9)
(1 - 2 - 3 + 45 - 6 - 7 + 8 * 9)
(1 * 2 + 34 + 5 - 6 - 7 + 8 * 9)
(12 + 34 - 5 - 6 - 7 + 8 * 9)
(12 - 3 - 4 + 5 * 6 - 7 + 8 * 9)
(1 - 2 * 3 - 4 - 5 + 6 * 7 + 8 * 9)
(1 + 2 - 3 * 4 - 5 + 6 * 7 + 8 * 9)
(1 + 2 + 3 - 4 * 5 + 6 * 7 + 8 * 9)
(1 * 2 * 3 - 4 * 5 + 6 * 7 + 8 * 9)
(1 + 23 - 4 + 56 / 7 + 8 * 9)
(1 * 2 + 34 - 56 / 7 + 8 * 9)
(1 - 2 - 3 + 4 * 56 / 7 + 8 * 9)
(1 * 234 + 5 - 67 - 8 * 9)
(1 + 234 - 56 - 7 - 8 * 9)
(1 + 2 + 34 * 5 + 6 - 7 - 8 * 9)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
(use srfi-1)

(define (atom? x)
  (not (or (null? x) (pair? x))))
(define (atom-list? ls)
  (and (pair? ls) (atom? (car ls))))

(define (my-flatten ls)
  (cond ((null? ls) '())
        ((pair? ls)
         (cond ((atom? (car ls)) (list ls))
               ((atom-list? (car ls))
                (append (list (car ls)) (my-flatten (cdr ls))))
               (else
                (append (my-flatten (car ls)) (my-flatten (cdr ls))))))
        (else (list ls))))

(define (_ a b)
  (cond ((< b 10) (+ (* a 10) b))
        ((< b 100) (+ (* a 100) b))
        ((< b 1000) (+ (* a 1000) b))
        ((< b 10000) (+ (* a 10000) b))
        ((< b 100000) (+ (* a 100000) b))
        ((< b 1000000) (+ (* a 1000000) b))
        ((< b 10000000) (+ (* a 10000000) b))
        ((< b 100000000) (+ (* a 100000000) b))
        ((< b 1000000000) (+ (* a 1000000000) b))
;        (else #f)
        ))

(define ops '(_ + - * /))

(define (apply-op op x y)
  (case op
    ((_) (_ x y))
    ((+) (+ x y))
    ((-) (- x y))
    ((*) (* x y))
    ((/) (/ x y))
    ))

(define (apply-rev-op op x y)
  (case op
;    ((_) (_ x y))
    ((+) (- x y))
    ((-) (+ x y))
    ((*) (/ x y))
    ((/) (* x y))))

(define (komachi n sum)
  (define (append-op-n ls op n) (append ls (list op n)))

  (define (1..k= k p)
; [1..k] = p となる組み合わせ
    (if (= 1 k) ;
      ; 1 = 1   ; p!=1ならアウト
        (if (= p 1) '((1)) '())
    ; [1..k-1] ?? k = p
        (my-flatten (map (lambda (op) (1..k (- k 1) op k p)) ops))
        ))

  (define (eval-exp exp)
    (define (iter rest product)
      (cond ((null? rest) product)
            ((eq? '* (car rest))
             (iter (cddr rest) (* product (cadr rest))))
            ((eq? '/ (car rest))
             (iter (cddr rest) (/ product (cadr rest))))
            ))
    (iter (cdr exp) (car exp)))

  (define (1..k?<..>= k op exp p)
; [1..k] op (exp) = p
    (if (= 1 k)
        (case op
          ((_)
           (let1 exp* (cons (_ 1 (car exp)) (cdr exp))
                 (if (= (eval-exp exp*) p)
                     exp*
                     '())))
          ((+ -) ; 1 +- exp = p
           (if (= (apply-op op 1 (eval-exp exp)) p)
               (append (list 1 op) exp)
               '()))
          ((* /)
           (let1 exp* (append (list 1 op) exp)
                 (if (= (eval-exp exp*) p)
                     exp*
                     '())))
          )
        (case op
          ((_)
           (my-flatten
            (map (lambda (op2) (1..k?<..>= (- k 1) op2 (cons (_ k (car exp)) (cdr exp)) p)) ops)))
          ((+ -)
           (map (lambda (x) (append x (list op) exp))
                (my-flatten (1..k= k (apply-rev-op op p (eval-exp exp))))
                ))
          ((* /)
           (my-flatten
            (map (lambda (op2) (1..k?<..>= (- k 1) op2 (append (list k op) exp) p)) ops)))
          )
        ))

  (define (1..k k op n p)
; [1..k] op n = p となる組み合わせが全部ほしい
    (if (= 1 k)
      ;k=1 : [1] op n = p
        (case op
          ((_)
           (if (= (_ 1 n) p) (list (_ 1 n)) '()))
          ((+ -)
           (if (= (apply-op op 1 n) p) (list 1 op n) '()))
          ((*)
           (if (= n p) (list 1 '* n) '()))
          ((/) '()) ; 1/n (n>1) cannot be p
          )
      ;k>1
        (case op
          ((_); [1..k-1] ?? k_n = p
           (my-flatten (map (lambda (op2) (1..k (- k 1) op2 (_ k n) p)) ops)))
          ((+ -) ; [1..k] ± n = p ;
           (map (lambda (x) (append-op-n x op n))
                (my-flatten (1..k= k (apply-rev-op op p n)))))
          ((* /) ; [1..k] */ n = p :: [1..c] ? ([c+1..k] */ n) = p
           (my-flatten (map (lambda (op2) (1..k?<..>= (- k 1) op2 (list k op n) p)) ops)))
           ; 結合則が加減算とは違う
          )
        ))

  (remove null? (1..k= n sum)))

(map print (komachi 9 100))

pythonでナイーブな実装。
括弧なしで101個でした。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def komachi():
    num = range(1,10)
    ope = ["",".0+",".0-",".0*",".0/"]
    c = 1
    for x in xrange(5**8):
        formula = str(num[0])
        for n in range(1,9):
            formula += ope[x%5] + str(num[n])
            x /= 5
        if eval(formula) == 100:
           print formula,c
           c += 1
           

komachi()

「C# には eval が無いなぁ。動的コンパイルでもしようかな。あ待てよアレがあったな」 ということで C#2.0 + IronPython1.1 です。ところてんさんの #4728 を参考に、Python のコードを片っ端から生成して IronPython で Execute しています。komachi 関数は C# 側で作成。括弧なしで 101 個を、6分程度(orz)で調べ上げます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
using System.Collections.Generic;
using IronPython;
using IronPython.Hosting;
using IronPython.Runtime;
using IronPython.Runtime.Calls;
class Program {
    static void Main() {
        PythonEngine python = new PythonEngine();
        EngineModule module = python.CreateModule();
        Dictionary<string, object> locals = new Dictionary<string, object>();
        int count = 0;
        locals["komachi"] = new CallTarget2(delegate(object obj, object obj2) {
            if (obj2.Equals(100.0)) {
                count++;
                Console.WriteLine(obj + " = " + obj2);
            }
            return null;
        });
        DateTime before = DateTime.Now;
        foreach (string code in GenPythonCode()) {
            python.Execute(code, module, locals);
        }
        Console.WriteLine("time: {0}", DateTime.Now - before);
        Console.WriteLine("total: {0}", count);
    }
    static IEnumerable<string> GenPythonCode()
    {
        string[] ops = { "", ".0+", ".0-", ".0*", ".0/" };
        for (int i = 0; i < Math.Pow(ops.Length, 8); i++) {
            string code = "1";
            int j = i;
            foreach (char num in "23456789") {
                code += ops[j % ops.Length] + num;
                j /= ops.Length;
            }
            yield return string.Format("komachi(\"{0}\", {0})", code + ".0");
        }
    }
}

パーサコンビネータでパーサを作ってナイーブに。 解答は101個です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import scala.util.parsing.combinator.{Parsers, ImplicitConversions, ~, mkTilde}
import scala.util.parsing.combinator.syntactical.StdTokenParsers
import scala.util.parsing.combinator.lexical.StdLexical

object Komachi extends StdTokenParsers with Application{
  type Tokens = StdLexical ; val lexical = new StdLexical
  lexical.delimiters ++= List("+","-", "*", "/")
  def expr = term*("+" ^^ {(x: double, y: double) => x + y}
                 | "-" ^^ {(x: double, y: double) => x - y})
  def term = factor*("*" ^^ {(x: double, y: double) => x * y}
                   | "/" ^^ {(x: double, y: double) => x / y})
  def factor: Parser[double] = numericLit ^^ (_.toDouble)

  ((List(List[String]())) /: List.make(8, List("+", "-", "*", "/", ""))){
    for(i <-_; j <-_) yield j::i
  }.foreach{fs =>
    val s = (new StringBuilder("1") /: (2 to 9)){(s,i) =>
      s.append(fs(i-2)).append(i)
    }.toString
    if(expr(new lexical.Scanner(s)).get == 100.0) println(s)
  }
}

#4725 を参考にしました。printはRhinoのprintで。
重いので、ブラウザでは動かさないように。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function komachi() {
  var list = Array.prototype.slice.apply(arguments, [0]);
  var right = list.pop();
  var operator = ["", "+", "-", "*", "/"];
  var n = Math.pow(operator.length,list.length-1);

  for(var i=0; i<n; i++) {
    var exp = [list[0]];
    var o = (n+i).toString(5);
    for(var j=1, ii=i; j<list.length; j++) {
      exp.push(operator[o.slice(j,j+1)]);
      exp.push(list[j]);
      ii = Math.floor(i/5);
    }
    if(eval(exp.join("")) == right) print(exp.join("") + '=' + right);
  }
}
print("begin");
komachi(1,2,3,4,5,6,7,8,9,100);
print("end");

解答101個で4分弱でした。


秒殺です
% time gosh komachi.scm
(123 - 45 - 67 + 89)
(1 * 2 - 3 + 4 - 5 + 6 + 7 + 89)
中略
(1 + 234 - 56 - 7 - 8 * 9)
(1 + 2 + 34 * 5 + 6 - 7 - 8 * 9)

real	0m0.775s
user	0m0.758s
sys	0m0.015s


ナイーブに全探索。

opparseで演算子順位文法を使って式をRPNに変換し、calcで計算してます。

opsの定義を変えれば演算子を増やしたり優先順位を買えたりできます。同じ優先度の演算子は左結合。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import Numeric

data Item a b = Value a | Op (a->a->a) b [Char]

cat a b = a*10+b

ops :: [Item Double Integer]
ops = [Op cat 2 "", Op (+) 0 "+", Op (-) 0 "-", Op (*) 1 "*", Op (/) 1 "/"]
 
opparse [] _ vs = reverse vs
opparse (op:ops) (i:is) vs = opparse ops is $ push op (Value i) vs

push op@(Op o p _) v (op'@(Op o' p' _):vs)
  | (p <= p') = (op:v:op':vs)
  | otherwise = (op':push op v vs)
push op v vs = op:v:vs

calc [a] [] = a
calc ns ((Value a):vs) = calc (a:ns) vs
calc (a:b:ns) ((Op op _ _):vs) = calc ((op b a):ns) vs
calc _ _ = error "invalid stack state"

showFormula ops = "1" ++ rec [2..] ops where
   rec _ [] = ""
   rec (i:is) ((Op _ _ n):ops) = n ++ (showInt . round) i (rec is ops)

genops 0 = [[]]
genops n = [o:os | o <- map (ops!!) [0..4], os <- genops (n-1)]

komachi n = [ops | ops <- genops n, test 100 ops] where
   test sum ops = abs (sum - (calc [] $ opparse ops [2..] [Value 1])) <= 1.0e-10

main = putStr $ unlines $ map showFormula $ komachi 8

とりあえず適当に全探索。候補を5進8桁の整数と同一視して dotimes で回してます。結果は101 件、CLISP で 16 秒でした。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(defun apply-op (op x y)
  (case op
    (#\+ (+ x y))
    (#\- (- x y))
    (#\* (* x y))
    (#\/ (/ x y))
    (#\SPACE (+ (* 10 x) y))
    (t 't)))

(defun precedence (op) (case op ((#\+ #\-) 1) ((#\* #\/) 2) (t 3)))
(defun precedence< (op1 op2) (< (precedence op1) (precedence op2)))

(defun eval-string (s)
  (loop with vstack and opstack
    for c across s
    if (digit-char-p c) do
    (push (parse-integer (string c)) vstack)
    else if #1=(or (null opstack) (precedence< (car opstack) c)) do
    (push c opstack)
    else do
    (loop until #1# do
      #2=(setf vstack
               (cons (apply-op (pop opstack) (cadr vstack) (car vstack))
                     (cddr vstack))))
    (push c opstack)
    finally
    (loop for op in opstack do  #2#)
    (return (car vstack))))

(defun komachi ()
  (let ((s (copy-seq "1 2 3 4 5 6 7 8 9")))
    (dotimes (x (expt 5 8))
      (dotimes (i 8)
        (setf (elt s (+ i i 1)) (elt " +-*/" (rem (floor x (expt 5 i)) 5))))
      (if (= (eval-string s) 100) (write-line s)))))

順当な遅さです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# -*- coding: utf-8 -*-

from __future__ import division
import re

E = '1%s2%s3%s4%s5%s6%s7%s8%s9==100'
A = ['', '+', '-', '*', '/']
F = lambda n: [[i] + l for i in A for l in F(n-1)] if n > 1 else [[i] for i in A]
R = lambda s: s.replace('+', u'+').replace('-', u'-').replace('*', u'×').replace('/', u'÷').replace('==', u'=')

print '\n'.join([R(E % tuple(l)) for l in F(8) if eval(E % tuple(l))])

Javaでは、evalがないので自前でParseを行って計算してみました。

括弧対応なしで、約1秒で 101通りの結果がでました。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import java.util.ArrayList;
import java.util.List;

public class Sample104 {

    public static void komachi(int[] lhs, int rhs) {
        if (lhs.length == 0) return;

        List<Term> expression = new ArrayList<Term>();
        expression.add(new TermValue(lhs[0]));
        for (int index = 1; index < lhs.length; index++) {
            List<Term> work = new ArrayList<Term>(expression);
            expression.clear();
            for (Term term: work) {
                List<Term> list = createTerm(term, lhs[index]);
                expression.addAll(list);
            };
        }

        int counter = 1;
        for (Term term: expression) {
            if (term.getValue() == rhs) {
                System.out.println(counter++ + ": " + term.toString() + " = " + rhs);
            }
        }
    }
    private static List<Term> createTerm(Term lhs, int r) {
        List<Term> result = new ArrayList<Term>();
        Operator[] operators = Operator.values();
        for (int index = 0; index < operators.length; index++) {
            result.add(new TermData(operators[index], lhs, new TermValue(r)));
        }
        return result;
    }


    public enum Operator {
        None {
            public int getPriority() { return 10; }
            public double operate(double lhs, double rhs) { return lhs * 10 + rhs; }
            public String toString() { return ""; }
        },
        Plus {
            public int getPriority() { return 1; }
            public double operate(double lhs, double rhs) { return lhs + rhs; }
            public String toString() { return "+"; }
        },
        Minus {
            public int getPriority() { return 1; }
            public double operate(double lhs, double rhs) { return lhs - rhs; }
            public String toString() { return "-"; }
        },
        Times {
            public int getPriority() { return 2; }
            public double operate(double lhs, double rhs) { return lhs * rhs; }
            public String toString() { return "*"; }
        },
        Divide {
            public int getPriority() { return 2; }
            public double operate(double lhs, double rhs) { return lhs / rhs; }
            public String toString() { return "/"; }
        };

        public abstract int getPriority();
        public abstract double operate(double lhs, double rhs);
    }
    private static interface Term {
        public boolean isOperate();
        public double getValue();
    }
    private static class TermValue implements Term {
        public final int value;

        public TermValue(int val) {
            value = val;
        }
        public boolean isOperate() { return false; }
        public double getValue() {
            return value;
        }
        public String toString() { return String.valueOf(value); }
    }
    private static class TermData implements Term {
        public final Operator op;
        public final Term lhs;
        public final Term rhs;

        /**
         * 右辺は追加分と考えて、演算子の順序に従ってデータを正規化します。
         */
        public TermData(Operator o, Term l, Term r) {
            Operator operator = o;
            Term lterm = l;
            Term rterm = r;

            if (l.isOperate()) {
                TermData data = (TermData) l;
                if (operator.getPriority() > data.op.getPriority()) {
                    rterm = new TermData(operator, data.rhs, rterm);
                    lterm = data.lhs;
                    operator = data.op;
                }
            }
            op = operator;
            lhs = lterm;
            rhs = rterm;
        }
        public boolean isOperate() { return true; }
        public double getValue() {
            return op.operate(lhs.getValue(), rhs.getValue());
        }
        public String toString() {
            return lhs.toString() + op.toString() + rhs.toString();
        }
    }


    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        komachi(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}, 100);
        System.out.println();
        long end = System.currentTimeMillis();
        System.out.println("elipse: " + (end - start) + "(ms)");
    }
}

アルゴリズム的には一番月並み。MacBook Pro 2.33GHz で12秒。

#あ、関数名が微妙に

Dan the Perl Monger

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/local/bin/perl
use strict;
use warnings;
use B::Deparse;

sub komanechi {
    for my $i ( 1 .. 5**8 ) {
        my $formula = 1;
        for my $n ( 2 .. 9 ) {
            $formula .= ( '', qw{+ - * /} )[ $i % 5 ] . $n;
            $i /= 5;
        }
        next if  100 != eval $formula;
        print "$formula\n";
    }
}

komanechi;

余裕があったら...という要望が、いつの間にか仕様になってるなんてコトはいつものこと。括弧付きも計算できるように実装しとくけど、計算しない方向で。

計算式を、逆ポーランド形式に変換して計算(総当たり)。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#include <ctype.h>
#include <math.h>
#include <iostream>
#include <queue>
#include <stack>

std::queue<std::string> ToReversePolish(std::string strExp)
{
    std::queue<std::string> result;
    bool bNum = false;
    std::stack<char> buff;
    for (std::string::iterator p = strExp.begin(); p != strExp.end(); p++) {
        if (isspace(*p) != 0)
            continue;
        if ((*p >= '0') && (*p <= '9')) {
            if (bNum) { result.back() += *p; }
            else      { result.push( std::string(1, *p) ); }
        }
        else if ((*p == '*') || (*p == '/') || (*p == '+') || (*p == '-')) {
            while ((buff.empty() == false) && (buff.top() != '(') && (buff.top() != '+') && (buff.top() != '-')) {
                result.push( std::string(1, buff.top()) );
                buff.pop();
            }
            buff.push(*p);
        }
        else if (*p == ')') {
            while (buff.empty() == false) {
                if (buff.top() == '(') { buff.pop(); break; }
                result.push( std::string(1, buff.top()) );
                buff.pop();
            }
        }
        else { buff.push(*p); }
        bNum = ((*p >= '0') && (*p <= '9'));
    }
    while (buff.empty() == false) {
        result.push( std::string(1, buff.top()) );
        buff.pop();
    }
    return result;
}

bool CalcReversePolish(std::queue<std::string> exp, double& ans)
{
    std::stack<double> buff;
    while (exp.empty() == false) {
        if ((exp.front().compare("/") == 0) ||
            (exp.front().compare("*") == 0) ||
            (exp.front