覆面算 SEND+MORE=MONEY を解いてみました
http://www.itpl.co.jp/ocaml-nagoya/index.php?%A5%CD%A5%BF%B5%AD%CF%BF%B8%CB%2FSEND%2BMORE%3DMONEY
「もっと金送れ」かっこいい!調べてみたら、こういうのを覆面算っていうのですね、ちっとも知りませんでした。取り敢えず解いてみました。
type pairs = (char * int) list let toint (li : int list) = List.fold_left (fun a b -> (a * 10 + b)) 0 li;; let score (d : pairs) = let f l = (toint (List.map (fun a -> List.assoc a d) l)) in if (List.assoc 'S' d = 0) || (List.assoc 'M' d = 0) then 99999 else let sum = (f ['S'; 'E'; 'N'; 'D']) + (f ['M'; 'O'; 'R'; 'E']) and money = f ['M'; 'O'; 'N'; 'E'; 'Y'] in abs (sum - money) let compare' a b = compare (score a) (score b);; let exchange (pairs:pairs) char = let unused = List.nth (List.filter (fun elt -> not (List.mem elt (snd (List.split pairs))) ) [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]) (Random.int 2) in (char, unused) :: (List.remove_assoc char pairs) ;; let swap (pairs:pairs) a b = let char_a, num_a = List.nth pairs a and char_b, num_b = List.nth pairs b in (char_a, num_b)::(char_b, num_a):: (List.remove_assoc char_b (List.remove_assoc char_a pairs)) ;; let rec change (pairs:pairs) = match Random.int 9, Random.int 8 with | 8, idx -> exchange pairs (fst (List.nth pairs idx)) | a, b -> if a <> b then swap pairs a b else change pairs let print_score n pairs = Printf.printf "G%d: " n; List.iter (fun (char, num) -> Printf.printf "%c: %d " char num) pairs; Printf.printf "(%d)" (score pairs); print_newline () ;; let rec generation n list = let sorted = List.sort compare' (List.flatten (List.map (fun pairs -> [pairs; change pairs; change pairs; change pairs; change pairs;] ) list)) in print_score n (List.hd sorted); if (score (List.hd sorted)) = 0 then List.hd sorted else generation (n+1) (snd (List.fold_left (fun (i, res) pairs -> if i > 0 then i-1, pairs::res else i, res ) (300, []) sorted)) ;; let rec choose numbers = if List.length numbers < 8 then let n = Random.int 10 in choose (if List.mem n numbers then numbers else n::numbers) else numbers ;; let make_pairs list = function | 0 -> list | _ -> (List.combine ['S';'E';'N';'D';'M';'O';'R';'Y'] (choose []))::list ;; let main = Random.self_init (); generation 0 (make_pairs [] 300);;
頭を使わない偶然頼り方式、でもおかげで5秒くらいで解けます。
G0: R: 9 M: 4 S: 7 E: 1 N: 8 D: 6 O: 0 Y: 2 (29535) G1: Y: 9 M: 2 E: 8 N: 1 S: 7 D: 6 O: 0 R: 4 (10325) G2: M: 1 S: 9 E: 7 N: 8 D: 6 O: 0 R: 4 Y: 2 (39) G3: S: 9 M: 1 E: 7 N: 8 D: 6 O: 0 R: 4 Y: 2 (39) G4: R: 4 Y: 2 M: 1 S: 9 E: 7 N: 8 D: 6 O: 0 (39) G5: D: 4 E: 6 M: 1 R: 8 N: 7 S: 9 O: 0 Y: 2 (2) G6: E: 6 S: 9 N: 7 D: 4 M: 1 R: 8 O: 0 Y: 2 (2) G7: Y: 2 N: 7 D: 4 E: 6 R: 8 M: 1 S: 9 O: 0 (2) G8: E: 6 N: 7 R: 8 D: 4 S: 9 M: 1 O: 0 Y: 2 (2) G9: D: 5 E: 6 R: 8 M: 1 O: 0 N: 7 S: 9 Y: 2 (1) G10: R: 8 D: 7 Y: 2 N: 6 E: 5 S: 9 M: 1 O: 0 (0) 4.21s user 0.04s system 94% cpu 4.470 total
解が複数ある時ダメだよね。でもちゃんと解けたから満足!