0
0

More than 3 years have passed since last update.

数値と演算の組み合わせの問題を深さ優先探索で解く

Last updated at Posted at 2019-10-28

「数値と演算の組み合わせの問題」とはどういうことかと言いますと、先日Twitterに流れてきた投稿をみたらこんなんがありました。(元ネタがアレなので、問題の設定は変えてあります)

勇者は5種類の薬を持っている。

A. MPを半分にする薬
B. MPを900減らす薬
C. MPを2000増やす薬
D. MPを5倍にする薬
E. MPを500増やす薬

今のMPは0である。MPを3000にしたい場合、どの順序で薬を飲めばよいか?

普通に計算してもよいのですが、今回は計算機の力を使い総当たりでやってみしょう。
愚直にfor loopを薬の数だけ書くやり方もありますが、面倒くさいので深さ優先探索を使います。

# n: 計算途中のMP
# lst: 残っている薬
# hist: これまで使った薬
def calc(n, lst, hist):
    # 全て薬を使ったら、3000になっているかチェック
    if len(lst) == 0:
        if n == 3000:
            print(hist)
        return
    # 残っている薬でイテレーション
    for i in range(len(lst)):
        # 元のリストが変わると困るのでコピー
        l = lst[:]
        h = hist[:]
        oper, num = l[i]
        # これまで使った薬リストに選んだ薬を入れる
        h.append(l[i])
        # 使った薬をリストから消す
        l.pop(i)
        # 足し算か掛け算かで分ける
        if oper == '+':
            calc(n + num, l, h) 
        else:
            calc(n * num, l, h)

# 計算する
calc(0, [('*', 0.5), ('*', 5), ('+', -900), ('+', 500), ('+', 2000)], [])

再帰を使って総当りを表現した、何の変哲もない深さ優先探索です。
結果は以下。

[('+', -900), ('+', 2000), ('*', 5), ('+', 500), ('*', 0.5)]
[('+', 2000), ('*', 0.5), ('+', -900), ('+', 500), ('*', 5)]
[('+', 2000), ('*', 0.5), ('+', 500), ('+', -900), ('*', 5)]
[('+', 2000), ('+', -900), ('*', 5), ('+', 500), ('*', 0.5)]

たかだか$5!$=120通りの演算なので楽勝ですね。以上。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0