{- きっぷ問題のプログラム (和田) -} {- 計算結果は分数にして記憶する. このとき0で割ったときが問題になる. 1/0 は (1/1)/(0/1)=1/0 になり a をこれで割ると 0/1. これに10をたすとち ょうど10になるが, すでに整数を3つ使っているので, 最後は9までしか足せず, 4つの整数の場合は10になることはない. -} import List data Tree = Tip Int | Fork Char Tree Tree -- 先頭のCharは演算子 +,-,*,/ eval :: Tree -> (Int, Int) -- 2つのIntは分子と分母 eval (Tip x) = (x, 1) -- x を分数 x/1 とする eval (Fork '+' x y) = (b * c + d * a, a * c) -- b/a + d/c where (b, a) = eval x (d, c) = eval y eval (Fork '-' x y) = (b * c - d * a, a * c) -- b/a - d/c where (b, a) = eval x (d, c) = eval y eval (Fork '*' x y) = (b * d, a * c) -- b/a * d/c where (b, a) = eval x (d, c) = eval y eval (Fork '/' x y) = (b * c, a * d) -- b/a / d/c where (b, a) = eval x (d, c) = eval y instance Show Tree where -- (x 演算子 y)と表示する show (Tip x) = show x show (Fork o x y) = "(" ++ show x ++ [' ',o,' '] ++ show y ++ ")" evaltree :: Tree -> (Bool, Tree) -- Boolは「10が作れる」 evaltree t = (d > 0 && n == d * 10, t) where (n,d) = eval t trees :: (Char, Char, Char, [Int]) -> [(Bool, Tree)] --Char,..は3つの演算子 trees x= -- 以下は3つの演算子を使う5つの式の形に対応 evaltree(Fork o (Fork p (Fork q (Tip a) (Tip b)) (Tip c)) (Tip d)): evaltree(Fork o (Fork p (Tip a) (Fork q (Tip b) (Tip c))) (Tip d)): evaltree(Fork o (Fork p (Tip a) (Tip b)) (Fork q (Tip c) (Tip d))): evaltree(Fork o (Tip a) (Fork p (Fork q (Tip b) (Tip c)) (Tip d))): evaltree(Fork o (Tip a) (Fork p (Tip b) (Fork q (Tip c) (Tip d)))):[] where (o,p,q,[a,b,c,d])=x perm :: [Int]->[[Int]] -- 順列を作る perm [] = [[]] perm xs = [x:ys | x<-xs, ys<- perm (delete x xs)] good :: (Bool, Tree) -> Bool -- filter用にBool部分を取り出す good x = b where (b, t) = x make10 :: [Int] -> [(Bool, Tree)] -- 4整数をとり, (成否, 式)の列を返す make10 x = filter good (concat (map trees y)) where y = [(o,p,q,as)|o<-ops, p<-ops, q<-ops, as<-perm x] ops = ['+','-','*','/'] -- 例 -- Main> make10 [3,4,7,8] -- 10が作れる場合 -- [(True,((3 - (7 / 4)) * 8)),(True,(8 * (3 - (7 / 4))))] -- Main> make10 [1,0,2,3] -- 10が作れない場合 -- []