出勤簿の判断推理

detail.chiebukuro.yahoo.co.jp

知恵袋で見つけた判断推理の出勤簿の問題をPythonで解いてみた。(2) - rscの日記

# 同じものを含む順列

def perm(head, rest):

    if len(rest) == 0:
        return [head]

    else:
        res = []

        # set(集合)型で重複を削除、ソート
        data = sorted(set(rest))

        for i in data:

            # 配列の複製
            restx = rest[:]

            # 指定データ削除
            restx.remove(i)

            headx = head + [i]
            res += perm(headx, restx)

        return res

# A 3日
# B 5日
# C 4日
# D 3日
# E 4日

# 3日出勤パターン作成
pattern3 = perm([], ['o', 'o', 'o', 'x', 'x', 'x', 'x'])


# 4日出勤パターン作成
pattern4 = perm([], ['o', 'o', 'o', 'o', 'x', 'x', 'x'])


# 5日出勤パターン作成
pattern5 = perm([], ['o', 'o', 'o', 'o', 'o', 'x', 'x'])

'''
print(len(pattern3))
print(len(pattern4))
print(len(pattern5))
'''

# パターン絞り込み
# Aは1日おきに働いた(2日連続で休んだことはない)
a = [y for y in pattern3 if 'oxoxo' in ''.join(y)]

# Bは条件なし
b = pattern5

# Eは3日続けて休んだ
e = [y for y in pattern4 if 'xxx' in ''.join(y)]

# CとDは同じ日に働いたことはなかった
# EとDは同じ日に働いたことはなかった
# CとEは同じ日、DはCとEと違う日

'''
print(len(a))
print(len(b))
print(len(e))
'''

# 曜日ごとの出勤日数
days = [3, 4, 1, 3, 1, 4, 3]

for xa in a:
    for xb in b:
        for xe in e:

            # CはEと同じ日
            xc = xe

            # DはEと違う日
            xd = ['x' if i == 'o' else 'o' for i in xe]

            for v in zip(days, xa, xb, xc, xd, xe):
                
                if v[0] != v[1:].count('o'):
                    break
            else:
                print( '  日月火水木金土')
                print('A', ' '.join(xa))
                print('B', ' '.join(xb))
                print('C', ' '.join(xc))
                print('D', ' '.join(xd))
                print('E', ' '.join(xe))
                print('-' * 16)