論理パズル「論理包含の6兄弟」を気合いで解く

はじめに

こんにちは、Yukkinです。

先日、Chihiroが出した論理パズル「論理包含の6兄弟」、皆さんは解きましたでしょうか。まだ解いていない人は、面白い問題ですのでぜひ考えてみてください。

アキラ,カオル,サツキ,タクミ,ナギサ,ハルカは年齢が異なる男3人女3人の兄弟姉妹です。
アキラの兄ならばカオルです。
カオルの兄ならばサツキです。
サツキの姉ならばタクミです。
タクミの姉ならばナギサです。
ナギサの兄ならばハルカです。
このとき、6人を年上から順に並べてください。

解説は下の記事にあります。

この問題、私も考えてみましたが難しい問題でした……。

解説はエレガントに解いていますが、私は気合いで解いてみようと思います。

思考

この問題を考えるにあたり感じたこと。それは、6人を順番に並べる通り数は 6!=720 通りしかないということです。

6人の性別の組み合わせは20通りありますが、それを加味しても 720×20=14400 通りしかありません。14400通りくらいであれば、すべて試せば答えに辿り着くのではないか。気合いで解くと書いたのはそういうことです。

このような方法を全探索(または、力任せ探索)と呼びます。
【参考】力まかせ探索(Wikipedia)

とは言え、私が14400通り試していれば日が暮れますので、プログラム化します。

(気合いを入れるのは私ではなくPCということですね)

実装

import itertools

brothers = ["アキラ", "カオル", "サツキ", "タクミ", "ナギサ", "ハルカ"]
# 兄弟の並び順(全720通り)
brother_patterns = set(itertools.permutations(brothers))

sexs = [0, 0, 0, 1, 1, 1]
# 性別の組合せ(全20通り、0が男性、1が女性)
sex_patterns = set(itertools.permutations(sexs))

# 解答保存用list
brother_ans = []
sex_ans = []

# 兄弟check関数
# 「aの兄(姉)ならばbです」
def check(a, b, sex, brother_pattern, sex_pattern):
    # aが何番目に並んでいるかを確認
    index = brother_pattern.index(a)
    # aより前にb以外の兄(姉)がいないかを調べる
    for i in range(index):
        if sex_pattern[i] == sex and brother_pattern[i] != b:
            return False
    return True

# 全探索
for brother_pattern in brother_patterns:
    for sex_pattern in sex_patterns:
        # 問題文の条件を満たすかcheck
        if check("アキラ", "カオル", 0, brother_pattern, sex_pattern) \
            and check("カオル", "サツキ", 0, brother_pattern, sex_pattern) \
            and check("サツキ", "タクミ", 1, brother_pattern, sex_pattern) \
            and check("タクミ", "ナギサ", 1, brother_pattern, sex_pattern) \
            and check("ナギサ", "ハルカ", 0, brother_pattern, sex_pattern):
            # 条件を満たせば、解答保存用listに追加する
            brother_ans.append(brother_pattern)
            sex_ans.append(sex_pattern)

# 解答保存用listの中身を出力
print(brother_ans)
print(sex_ans)

プログラム実行!

無事、答えを得ることができました。

最後に

この解法はずるいですか?

論理パズルらしい解き方は、Chihiroのこちらの記事を参考にしてください。

では、また!