小町算
Posted feedbacks - Nested
Flatten 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))
|
秒殺です % 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
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()
|
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)
}
}
|
重いので、ブラウザでは動かさないように。
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分弱でした。
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
|
高階関数と有理数を使って書き直してみました。 一部私好みに書き換えています。
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 | import Ratio
data Item a b c = Value a | Op (b->b->b) c String
cat a b = a*10+b
ops :: [Item Integer Rational Integer]
ops = [Op cat 2 "", Op (+) 0 "+", Op (-) 0 "-", Op (*) 1 "*", Op (/) 1 "/"]
opparse ops = reverse $ foldl push [Value 1] (zip ops $ map Value [2..])
push (op'@(Op o' p' _):vs) opv@(op@(Op o p _), v)
| p <= p' = op:v:op':vs
| otherwise = op':push vs opv
push vs (op, v) = op:v:vs
calc vs = head $ foldl g [] vs where
g ns (Value a) = a%1:ns
g (a:b:ns) (Op op _ _) = op b a:ns
g _ _ = error "invalid stack state"
showFormula ops = concat $ ["1"] ++ zipWith (\(Op _ _ n) i -> n ++ show i) ops [2..]
genops n = sequence $ replicate n ops
komachi n = filter (test 100) $ genops n where
test sum ops = sum == (calc $ opparse ops)
|
とりあえず適当に全探索。候補を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;
|
逆ポーランドへの変換が変だったので修正+べき乗を。 個数あってても計算結果がちがったらあかんよな...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 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 134 135 136 137 138 139 140 141 | #include <ctype.h>
#include <math.h>
#include <iostream>
#include <queue>
#include <stack>
#include <complex>
bool ToReversePolish(std::string strExp, std::queue<std::string>& ans)
{
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 == '^') {
while ((buff.empty() == false) && (buff.top() != '(') &&
(buff.top() != '*') && (buff.top() != '/') &&
(buff.top() != '+') && (buff.top() != '-')) {
result.push( std::string(1, buff.top()) );
buff.pop();
}
buff.push(*p);
}
else if ((*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 == '+') || (*p == '-')) {
while ((buff.empty() == false) && (buff.top() != '(')) {
result.push( std::string(1, buff.top()) );
buff.pop();
}
buff.push(*p);
}
else if (*p == ')') {
bool bPair = false;
while ((buff.empty() == false) && (bPair == false)) {
bPair = (buff.top() == '(');
if (bPair == false)
result.push( std::string(1, buff.top()) );
buff.pop();
}
if (bPair == false)
return false;
}
else if (*p == '(') {
buff.push(*p);
}
else {
return false;
}
bNum = ((*p >= '0') && (*p <= '9'));
}
while (buff.empty() == false) {
if (buff.top() == '(')
return false;
result.push( std::string(1, buff.top()) );
buff.pop();
}
ans = result;
return true;
}
bool CalcReversePolish(std::string strExp, double& ans)
{
std::queue<std::string> exp;
if (ToReversePolish(strExp, exp) == false)
return false;
std::stack<double> buff;
while (exp.empty() == false) {
if ((exp.front().compare("^") == 0) ||
(exp.front().compare("/") == 0) ||
(exp.front().compare("*") == 0) ||
(exp.front().compare("+") == 0) ||
(exp.front().compare("-") == 0) ) {
if (buff.size() < 2)
return false;
double b = buff.top(); buff.pop();
double a = buff.top(); buff.pop();
if ((exp.front().compare("/") == 0) && (b == 0.0))
return false;
if (exp.front().compare("^") == 0) { buff.push(std::pow(a, b)); }
else if (exp.front().compare("/") == 0) { buff.push(a / b); }
else if (exp.front().compare("*") == 0) { buff.push(a * b); }
else if (exp.front().compare("+") == 0) { buff.push(a + b); }
else if (exp.front().compare("-") == 0) { buff.push(a - b); }
}
else {
buff.push( atof(exp.front().c_str()) );
}
exp.pop();
}
if (buff.size() != 1)
return false;
ans = buff.top();
return true;
}
void komachi()
{
int nCount = 0;
int nError = 0;
char szExp[50];
strcpy(szExp, "1 2 3 4 5 6 7 8 9");
bool bLast = false;
while (bLast == false) {
double ans = 0.0;
if (CalcReversePolish(szExp, ans) != false) {
if (ans == 100.0) {
std::cout << szExp << "=" << ans << std::endl;
nCount++;
}
}
else {
nError++;
}
for (int n = 7; n >= 0; n--) {
if (szExp[n * 2 + 1] == ' ') { szExp[n * 2 + 1] = '*'; break; }
if (szExp[n * 2 + 1] == '*') { szExp[n * 2 + 1] = '/'; break; }
if (szExp[n * 2 + 1] == '/') { szExp[n * 2 + 1] = '+'; break; }
if (szExp[n * 2 + 1] == '+') { szExp[n * 2 + 1] = '-'; break; }
szExp[n * 2 + 1] = ' ';
bLast = ((n == 0) && (szExp[n * 2 + 1] == ' '));
}
}
std::cout << "count = " << nCount << std::endl;
std::cout << "error = " << nError << std::endl;
}
|
101件確認しました.
1 2 3 4 5 | komati([X], N, X) :- term_to_atom(T, X), N =:= T.
komati([X1,X2|Xs], N, S) :- member(Op, [+,-,*,/,'']),
concat_atom([X1,Op,X2], X3), komati([X3|Xs], N, S).
:- forall(komati([1,2,3,4,5,6,7,8,9], 100, S), writeln(S)).
|
1 2 3 4 5 6 7 8 9 | function doukaku104(exp, ops){
var d = new Date, x = /□/g, f = function(t){ t = ops[i % o], i = i / o | 0; return t };
for(var R = [], r = 0, o = ops.length, n = Math.pow(o, exp.match(x).length), i, e; i = n--;)
if(eval(e = exp.replace(x, f))) R[r++] = e;
return R[r] = R.length +' results / '+ (new Date - d) +'[ms]', R.join('\n');
}
(typeof print != 'undefined' ? print : function($){ WSH.echo($) })
(doukaku104('1□2□3□4□5□6□7□8□9==100', ['', '+', '-', '*', '/']));
|
eval(Compiler class>>#evaluate:)を使いたかったのですが、Smalltalk には四則演算で乗除の優先がないので断念(^_^;)。Squeak OMeta でパーサー&インタープリタを書いて、それに eval 相当の仕事を肩代わりさせています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | !OMeta methodsFor: 'calc'!
num ::= <digit>+:xs => [Integer readFrom: xs readStream]! !
!OMeta methodsFor: 'calc'!
mul ::= <mul>:x ( $* <num>:y => [x * y] | $/ <num>:y => [x / y] ) | <num>! !
!OMeta methodsFor: 'calc'!
add ::= <add>:x ( $+ <mul>:y => [x + y] | $- <mul>:y => [x - y] ) | <mul>! !
!OMeta methodsFor: 'calc'!
exp ::= <add>! !
World findATranscript: nil.
#('' '+' '-' '*' '/') asDigitsToPower: 8 do: [:comb |
| expStr result |
expStr := '1{1}2{2}3{3}4{4}5{5}6{6}7{7}8{8}9' format: comb.
result := (OMeta onTree: nil) apply: #exp withArguments: expStr.
result = 100 ifTrue: [Transcript cr; show: expStr]]
|
が、メモリエラーが発生(memory_limit = 32Mの設定)したため、
とりあえず8を追加するときに、9を加減する場合のみ前計算して不要なものを排除。
101件取得(33.56秒)
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 | $operators = array( '+', '-', '*', '/', '' );
for ( $i = 1; $i <= 9; $i ++ ) {
$h = 1;
if ( $i == 1 ) {
foreach ( $operators as $row ) {
$temp[$h] = $i . $row;
$h++;
}
} elseif ( $i == 9 ) {
foreach ( $temp as $row ) {
$expression = $row . $i;
eval("\$ans = $expression;");
if ( $ans == 100 ) {
$expressions[] = $expression;
}
$h++;
}
} else {
if ( $i == 8 ) {
foreach ( $temp as $row ) {
foreach ( $operators as $key => $val ) {
$expression_temp = $row . $i;
eval("\$ans = $expression_temp;");
if ( $key === 0 ) {
if ( $ans == 91 ) {
$temp[$h] = $row . $i . $val;
$h++;
}
} elseif ( $key == 1 ) {
if ( $ans == 109 ) {
$temp[$h] = $row . $i . $val;
$h++;
}
} else {
$temp[$h] = $row . $i . $val;
$h++;
}
}
}
} else {
foreach ( $temp as $row ) {
foreach ( $operators as $row2 ) {
$temp[$h] = $row . $i . $row2;
$h++;
}
}
}
}
}
print_r($expressions);
|
ocamlyaccとかストリームパーサーとか色々な道具を試した結果、LL(1) 再帰下降パーサーを手書きしました。
計算途中の値はint*int型の分数で持っています。
結果は101件で実行時間は0.23秒でした。
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 | type token = Int of int | Mul | Div | Add | Sub
let add (a1, b1) (a2, b2) = (a1 * b2 + a2 * b1), (b1 * b2)
let sub (a1, b1) (a2, b2) = (a1 * b2 - a2 * b1), (b1 * b2)
let mul (a1, b1) n = (a1 * n), b1
let div (a1, b1) n = a1, (b1 * n)
let factor list =
let rec factor' n = function
| Int x :: tl -> factor' (n * 10 + x) tl
| x -> n, x in
factor' 0 list
let term input =
let rec term' (f,input) = match input with
| Mul :: tl -> let f2, tl2 = factor tl in term' ((mul f f2), tl2)
| Div :: tl -> let f2, tl2 = factor tl in term' ((div f f2), tl2)
| x -> f, x in
let n, input = factor input in term' ((n,1), input)
let expr input =
let rec expr' (f,input) = match input with
| Add :: tl -> let f2, tl2 = term tl in expr' ((add f f2), tl2)
| Sub :: tl -> let f2, tl2 = term tl in expr' ((sub f f2), tl2)
| _ -> f in
expr' (term input)
let op = [| Add; Sub; Mul; Div |]
let rec makeexpr list o n =
if n = 0 then list else match (o mod 5) with
| 4 -> makeexpr (Int n :: list) (o / 5) (n - 1)
| x -> makeexpr (Int n :: op.(x) :: list) (o / 5) (n - 1)
let rec makestr s = function
| [] -> s
| hd :: tl -> makestr (s ^ (match hd with
| Int x -> string_of_int x | Mul->"*" | Div->"/" | Add->"+" | Sub->"-")) tl
let rec main n = if n >= 0 then
let ex = makeexpr [ Int 9 ] n 8 in
let a, b = expr ex in
let _ = if b * 100 = a then Printf.printf "%s\n" (makestr "" ex) in
main (n - 1)
let _ = main 390624
|
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 | #include <stdio.h>
#include <math.h>
#define PART_MULT '*'
#define PART_DIV '/'
#define PART_PLUS '+'
#define PART_MINUS '-'
#define PART_DIGIT ' '
#define PART_EQ '='
#define NPART 9
typedef struct {
int num;
char csim;
} exppart_t;
void display_exp(exppart_t *epart)
{
int i;
for (i = 0; i < NPART; i++) {
printf("%d %c ", epart[i].num, epart[i].csim);
if (epart[i].csim == '=') {
printf("\n");
return;
}
}
printf("\n");
}
void shift_exp(exppart_t *epart, int offset, int n)
{
int i;
for (i = offset; i < NPART; i++) {
if (i + n < NPART) {
epart[i] = epart[i + n];
} else {
epart[i].csim = '=';
epart[i].num = 0;
}
}
}
int adigit_exp(exppart_t *epart) {return (epart->num * 10 + (epart+1)->num);}
int aplus_exp(exppart_t *epart) {return (epart->num + (epart+1)->num);}
int aminus_exp(exppart_t *epart) {return (epart->num - (epart+1)->num);}
int amult_exp(exppart_t *epart) {return (epart->num * (epart+1)->num);}
int adiv_exp(exppart_t *epart) {return (epart->num / (epart+1)->num);}
void acalc_exp(exppart_t *epart, char cparts, int (*acalc)(exppart_t*))
{
int i;
for (i = 0; i < NPART-1; i++) {
if (epart[i].csim == cparts) {
epart[i].num = acalc(epart+i);
epart[i].csim = epart[i+1].csim;
shift_exp(epart, i + 1, 1);
break;
}
}
}
void proc_calc_exp(exppart_t *epart, char cparts, int (*acalc)(exppart_t*))
{
int i;
for (i = 0; i < NPART-1; i++) {
acalc_exp(epart, cparts, acalc);
}
}
int isdivable(exppart_t *epart) {
int i, vmem = epart[0].num;
for (i = 0; i < NPART-1; i++) {
if (epart[i].csim == PART_DIV) {
if (vmem % epart[i+1].num != 0) {
return 0;
}
} else {
vmem = epart[i+1].num;
}
}
return 1;
}
void komachi() {
exppart_t epart[NPART], epart_def[NPART];
char simpart[] = {PART_MULT, PART_DIV, PART_PLUS, PART_MINUS, PART_DIGIT};
int i, cnt;
long li, limax;
cnt = 0;
limax = (long)pow(5.0, NPART-1.0);
for (li = 0; li < limax; li++) {
for (i = 0; i < NPART; i++) {
epart[i].csim = simpart[(li / (long)pow(5.0, i)) % 5];
}
epart[NPART-1].csim = PART_EQ;
for (i = 0; i < NPART; i++) {
epart[i].num =i + 1;
epart_def[i] = epart[i];
}
proc_calc_exp(epart, PART_DIGIT, adigit_exp);
proc_calc_exp(epart, PART_MULT, amult_exp);
if (!isdivable(epart)) {
continue;
}
proc_calc_exp(epart, PART_DIV, adiv_exp);
proc_calc_exp(epart, PART_PLUS, aplus_exp);
proc_calc_exp(epart, PART_MINUS, aminus_exp);
if (epart[0].num == 100) {
cnt++;
display_exp(epart_def);
}
}
printf("count : %d\n", cnt);
}
int main()
{
komachi();
return 0;
}
|
日記の方に一度書いたソースですが、そのまま載せます。
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 | from __future__ import division
import itertools
def permutation(*args):
D = dict([(id(L), L) for L in args])
def permutation_(*args):
if not args:
yield []
elif len(args) == 1:
D[id(args[0])], g = itertools.tee(D[id(args[0])])
for x in g:
yield [x]
else:
D[id(args[0])], g = itertools.tee(D[id(args[0])])
for x in g:
for y in permutation_(*args[1:]):
yield [x] + y
return permutation_(*args)
c = itertools.count(1)
ops = ['+', '-', '*', '/', '']
L = ['1', ops, '2', ops, '3', ops, '4', ops, '5', ops, '6', ops, '7', ops, '8', ops, '9']
for exp in permutation(*L):
exp = ''.join(exp)
if eval(exp) == 100:
print exp, c.next()
|
演算子配列の重複順列と数字とを`zip'を利用して交互に配置して`eval'で評価しました. 実行時間はP4 2.4GHzで3分間程度.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | module Enumerable
def rperm(n=size, out=[], &block) #重複順列生成
n <= 0 ? (yield out) : each{|x| rperm(n-1, [x,*out], &block)}
end
end
def komachi(n=9)
soln = []
seq = (1..n-1).to_a
['+', '-', '*', '/', ''].rperm(n-1){|opr|
eqn = "#{seq.zip(opr).to_a.join}#{n}"
eqn.gsub!(/\/(\d+)/){"\/#{$1}.0"} #floatとして計算させるため
soln << eqn if eval(eqn) == 100}
soln
end
|
1 2 3 4 5 6 7 8 9 10 11 12 | def komachi(n = 2, e = "1")
if n == 10
p e if eval(e.gsub(' ','.0')) == 100
else
"+-*/".split("").each{|i|
komachi(n + 1, e + " " + i + n.to_s)
}
komachi(n + 1, e + n.to_s)
end
end
komachi
|
重たすぎです。 1.java実行形式にコンパイル 2.combi.eachをfor文に書き換える としたら何とか動くようになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import static groovy.util.GroovyCollections.combinations
import groovy.util.Eval
def operations = ["", "+", "-", "*", "/"]
def combi = combinations((1..8).collect{ operations })
def eval = new Eval()
combi.each{ opes ->
def text = "1${opes[0]}2${opes[1]}3${opes[2]}4${opes[3]}5${opes[4]}6${opes[5]}7${opes[6]}8${opes[7]}9"
if( eval.me(text) == 100 ){
println "${text} = 100"
}
}
|
Eval使いました。
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 | using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.JScript.Vsa;
using Microsoft.JScript;
static class Program {
[STAThread]
static void Main() {
string[] s1 = new string[] { "2","3","4","5","6","7","8","9" };
string[] s2 = new string[] { "","+","-","*","/" };
int max = (int)Math.Pow(5,8);
for(int i = 0;i <= max;i++) {
string rslt = "1";
int iCopy = i;
foreach(string s in s1) {
rslt += s2[iCopy % 5] + s;
iCopy /= 5;
}
VsaEngine ve = VsaEngine.CreateEngine();
double r = System.Convert.ToDouble(Eval.JScriptEvaluate(rslt,ve));
if(r == 100.0) {
Console.WriteLine(rslt);
}
}
}
}
|
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 | ※【なでしこ実行モード】cnako
候補[0]に「」を代入する
候補[1]に「+」を代入する
候補[2]に「-」を代入する
候補[3]に「*」を代入する
候補[4]に「/」を代入する
発見数に0を代入する
枠1で0から4まで繰り返す
枠2で0から4まで繰り返す
枠3で0から4まで繰り返す
枠4で0から4まで繰り返す
枠5で0から4まで繰り返す
枠6で0から4まで繰り返す
枠7で0から4まで繰り返す
枠8で0から4まで繰り返す
計算式に「1{候補[枠1]}2{候補[枠2]}3{候補[枠3]}4{候補[枠4]}5{候補[枠5]}6{候補[枠6]}7{候補[枠7]}8{候補[枠8]}9」を代入する
計算式でナデシコする
もし、それが100ならば
発見数に1を直接足す
「{発見数}. {計算式} = 100」と表示
「{改行}全部で{発見数}コありました!」と表示
|
C++ですがCみたいなコードになってしまいました
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 | #include <cstdio>
#include <cmath>
const int EXPRSIZ = 17;
enum { _ = -5, ADD, SUB, MUL, DIV };
const int operators[] = { _, ADD, SUB, MUL, DIV };
int priority(double op)
{
switch (static_cast<int>(op)) {
case _: return 3;
case ADD: case SUB: return 1;
default: return 2;
}
}
void torpn(const double *expr, double *rpn)
{
double stack[EXPRSIZ];
int sp = 0;
for (const double *endp = expr + EXPRSIZ; expr != endp; ++expr) {
if (*expr > 0) *rpn++ = *expr;
else {
int pri = priority(*expr);
if (!sp || pri > priority(stack[sp-1])) stack[sp++] = *expr;
else {
do *rpn++ = stack[--sp];
while (sp > 0 && pri <= priority(stack[sp-1]));
stack[sp++] = *expr;
}
}
}
while (sp > 0) *rpn++ = stack[--sp];
}
double eval(const double *rpn)
{
double stack[EXPRSIZ];
int sp = 0;
for (const double *endp = rpn + EXPRSIZ; rpn < endp; ++rpn) {
if (*rpn > 0) stack[sp++] = *rpn;
else {
double y = stack[--sp], x = stack[--sp];
switch (static_cast<int>(*rpn)) {
case _: stack[sp++] = x * 10 + y; break;
case ADD: stack[sp++] = x + y; break;
case SUB: stack[sp++] = x - y; break;
case MUL: stack[sp++] = x * y; break;
case DIV: stack[sp++] = x / y; break;
}
}
}
return stack[sp-1];
}
void print(double *expr)
{
for (int i = 0; i < EXPRSIZ; ++i)
if (expr[i] > 0)
std::printf("%g", expr[i]);
else if (expr[i] != _)
std::printf(" %c ", "+-*/"[static_cast<int>(expr[i]) + 4]);
std::putchar('\n');
}
int main()
{
double expr[] = { 1., 0., 2., 0., 3., 0., 4., 0., 5.,
0., 6., 0., 7., 0., 8., 0., 9. };
double rpn[EXPRSIZ], stack[EXPRSIZ];
for (int i = 0, limit = static_cast<int>(std::pow(5., 8.)); i < limit; ++i) {
for (int n = i, j = 0; j < 8; ++j, n /= 5)
expr[2 * j + 1] = operators[n % 5];
torpn(expr, rpn);
if (eval(rpn) == 100.0) print(expr);
}
}
|
別にintでいいところまでdoubleにしてました。やりなおし。
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 | #include <cstdio>
#include <cmath>
const int EXPRSIZ = 17;
enum { _ = -5, ADD, SUB, MUL, DIV };
const int operators[] = { _, ADD, SUB, MUL, DIV };
int priority(int op)
{
switch (op) {
case _: return 3;
case ADD: case SUB: return 1;
default: return 2;
}
}
void torpn(const int *expr, int *rpn)
{
int stack[EXPRSIZ];
int sp = 0;
for (int i = 0; i < EXPRSIZ; ++i) {
if (expr[i] > 0) *rpn++ = expr[i];
else {
int pri = priority(expr[i]);
if (!sp || pri > priority(stack[sp-1]))
stack[sp++] = expr[i];
else {
do *rpn++ = stack[--sp];
while (sp > 0 && pri <= priority(stack[sp-1]));
stack[sp++] = expr[i];
}
}
}
while (sp > 0) *rpn++ = stack[--sp];
}
double eval(const int *rpn)
{
double stack[EXPRSIZ];
int sp = 0;
for (int i = 0; i < EXPRSIZ; ++i) {
if (rpn[i] > 0) stack[sp++] = static_cast<double>(rpn[i]);
else {
double y = stack[--sp], x = stack[--sp];
switch (rpn[i]) {
case _: stack[sp++] = x * 10 + y; break;
case ADD: stack[sp++] = x + y; break;
case SUB: stack[sp++] = x - y; break;
case MUL: stack[sp++] = x * y; break;
case DIV: stack[sp++] = x / y; break;
}
}
}
return stack[sp-1];
}
void print(const int *expr)
{
for (int i = 0; i < EXPRSIZ; ++i)
if (expr[i] > 0)
std::printf("%d", expr[i]);
else if (expr[i] != _)
std::printf(" %c ", "+-*/"[expr[i] + 4]);
std::putchar('\n');
}
int main()
{
int expr[] = { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9 };
int rpn[EXPRSIZ], limit = static_cast<int>(std::pow(5.,8.));
for (int i = 0; i < limit; ++i) {
for (int n = i, j = 0; j < 8; ++j, n /= 5)
expr[2 * j + 1] = operators[n % 5];
torpn(expr, rpn);
if (eval(rpn) == 100.) print(expr);
}
}
|
演算子の重複順列を5進数00000000から44444444で表現して総当たり。
10進数を"%08d" % i.to_s(5)で8桁の5進数に変換。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | n = (1..9).to_a
op = ["",".0/","+","-","*"]
for i in 0..((5**8)-1)
a = n.zip(("%08d" % i.to_s(5)).chars.map{|j|op[j.to_i]}).to_s
puts a.tr("*/+-","×÷+-").concat("=#{eval(a)}").gsub(/\.0/,"") if eval(a) == 100.0
end
# => 123+45-67+8-9=100
# => 123+4-5+67-89=100
# => 123+4×5-6×7+8-9=100
# => 123-45-67+89=100
# => 123-4-5-6-7+8-9=100
# => 12÷3÷4+5×6+78-9=100
# => 12÷3+4×5-6-7+89=100
# => 12÷3+4×5×6-7-8-9=100
# => 12÷3+4×5×6×7÷8-9=100
# => 12+34+5×6+7+8+9=100
#...101個表示。
|
小数点以下の計算が必要なのは、割り算のときだけという事を利用して、#6188を倍速化しました。
1 2 3 4 5 6 7 8 9 10 11 12 | OP = "+ - * .0/".split(/ /)
def komachi(n = 2, e = '1')
if n == 10
p e if eval(e) == 100
else
OP.each{|i|
komachi(n + 1, e + i + n.to_s)
}
komachi(n + 1, e + n.to_s)
end
end
|
Tcl8.6b からcoroutine が導入されたので練習も兼ねて。
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 | package require Tcl 8.6
proc A {} {
foreach x {{{}} + - * /} { B [list $x] }
}
proc cat coro {
while 1 {
set input [yield]
foreach x {{{}} + - * /} { $coro [concat $input $x] }
}
}
coroutine B cat C
coroutine C cat D
coroutine D cat E
coroutine E cat F
coroutine F cat G
coroutine G cat H
coroutine H cat print
coroutine print apply {{} {
while 1 {
lassign [yield] a b c d e f g h
set exp [join "1 $a 2 $b 3 $c 4 $d 5 $e 6 $f 7 $g 8 $h 9" {}]
set num [expr [string map {/ *1.0/} $exp]]
if {$num == 100.0} { puts "$exp = 100" }
}
}}
puts [time A]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function komachi([int] $i, [string] $expr)
{
if ($i -gt 10)
{
$sum = Invoke-Expression $expr
if ($sum -eq 100)
{
Write-Output ("$expr = $sum")
}
}
else
{
komachi ($i + 1) ($expr + " + $i")
komachi ($i + 1) ($expr + " - $i")
komachi ($i + 1) ($expr + " * $i")
komachi ($i + 1) ($expr + " / $i")
}
}
komachi 2 '1'
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function komachi([int] $i, [string] $expr)
{
if ($i -gt 10)
{
$sum = Invoke-Expression $expr
if ($sum -eq 100)
{
Write-Output ("$expr = $sum")
}
}
else
{
komachi ($i + 1) ($expr + " + $i")
komachi ($i + 1) ($expr + " - $i")
komachi ($i + 1) ($expr + " * $i")
komachi ($i + 1) ($expr + " / $i")
komachi ($i + 1) ($expr + [string]$i)
}
}
komachi 2 '1'
|
PHP勉強中
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 | <?php
print <<< END_DOC
<HTML>
<HEAD><title>doukaku104</title>
</HEAD><BODY>
END_DOC;
function doukaku104()
{
$num = array("1", "2", "3", "4", "5", "6", "7", "8", "9");
$ope = array("","+", "-", "*", "/");
$total = 0;
for($i = 0; $i < pow(5,8); $i++){
$t =$i;
$s = "";
for($j = 0; $j < 8; $j++){
$s .= $num[$j] . $ope[$t % 5];
$t /= 5;
}
$s .= $num[8];
$n = eval("return (".$s.");");
if ($n == 100) {
print "$s = $n<BR>";
$total++;
}
}
print "total=$total";
}
doukaku104();
print <<< END_DOC
</BODY>
</HTML>
END_DOC;
?>
|






dpp
#4509()
Rating0/2=0.00
古典的なパズルである小町算を解くプログラムを作成してください。
小町算とは:
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
手元で20数行ほどのPythonスクリプトを書いてみたところ、101個の解答が得られました。
[ reply ]