知恵袋で見つけた判断推理の出勤簿の問題をPythonで解いてみた。

 知恵袋で見つけた判断推理の出勤簿の問題Pythonで解いてみました。

 A〜Eの5人はある事業所に勤務する派遣社員である。この5人のある月曜日から金曜日までの出勤状況について次のことがわかっているとき、正しくいえるのはどれか。
ア、月曜日から木曜日はそれぞれ3人、金曜日は4人が出勤した。
イ、A〜Eはいずれも3日以上出勤した。
ウ、BとEの出勤日はすべて同じであった。
エ、Cは4日連続で出勤した。
オ、Dは1日おきに出勤した。<選択肢>
1、Aは火曜日に出勤した。
2、Bは水曜日に出勤した。
3、Cは金曜日に出勤した。
4、DとAの出勤した日は1日だけ異なった。
5、EとAの出勤した日は1日だけ重なった。

※ただし、条件にア〜オの名前を付けました。(^_^;

 月火水木金 日数
A□□□□□ ≧3
B□□□□□ ≧3
C□□□□□ ≧3
D□□□□□ ≧3
E□□□□□ ≧3
人33334
数

 一番目の参考URLから、hasWorked()関数中で曜日を1文字で表すのに、'MTWRF'を用いました。
 選択肢の4番をどう表すかで苦労しました。Cが4日連続で出勤しているので、残りのDとAは3日出勤しているから、出勤日が2日重なったことになります。あるいは、DとAの出勤数を調べて大きい方から1を引いてもいいのかな。(^_^;

● AttendanceBook1.py

# coding: UTF-8
# AttendanceBook1.py

import itertools
from time import time

# 曜日ごとの出勤者数のチェック
def chechAttendance(la, ls):
    for i in range(len(ls)):
        t = 0
        for j in range(len(la)):
            t+=1 if la[j][i]=='o' else 0
        if t!=ls[i]: return False
    return True

# 出勤表laからc曜日に働いたか調べる
# M:月; T:火; W:水; R:木; F:金
def hasWorked(la, c):
    WD = 'MTWRF'
    return la[WD.index(c)]=='o'

# 一緒に出勤した日数を調べる
def numOfDaysTog(la,lb):
    c = 0
    for i in range(len(la)):
        if la[i]=='o' and lb[i]=='o': c+=1
    return c

# 結果を表示
def PrintResult(lst):
    n = len(lst)
    NAME = 'ABCDE'
    print(' MTWTF')
    for i in range(n):
        print(NAME[i]+''.join(lst[i]))
    print('')

def main():
    tm=time()  # Timer Start
    S = [3,3,3,3,4]     # 曜日ごとの働いた人数

    ch = [True]*5
    cnt = 0
    for a in itertools.product('ox',repeat=5):
        sa = ''.join(a)                     # Aの出勤表1行を文字列で得る
        if not sa.count('o')>=3: continue                       # 条件イ
        for b in itertools.product('ox',repeat=5):
            sb = ''.join(b)                 # Bの出勤表1行を文字列で得る
            if not sa.count('o')>=3: continue                   # 条件イ
            for c in itertools.product('ox',repeat=5):
                sc = ''.join(c)             # Cの出勤表1行を文字列で得る
                if not sc.count('o')>=3: continue               # 条件イ
                if 'oooo' not in sc: continue                   # 条件エ
                for d in itertools.product('ox',repeat=5):
                    sd = ''.join(d)         # Dの出勤表1行を文字列で得る
                    if not sd.count('o')>=3: continue           # 条件イ
                    if 'oo' in sd or 'xx' in sd: continue       # 条件オ
                    for e in itertools.product('ox',repeat=5):
                        se = ''.join(e)     # Eの出勤表1行を文字列で得る
                        if not se.count('o')>=3: continue
                        if sb!=se: continue                     # 条件ウ
                        li = [a,b,c,d,e]
                        if not chechAttendance(li,S): continue  # 条件ア
                        # チェックを潜り抜けたものだけを表示
                        cnt+=1
                        print("[%d]"%cnt)
                        PrintResult(li)
                        # 選択肢のチェック
                        ch[0] &= hasWorked(a,'T')
                        ch[1] &= hasWorked(b,'W')
                        ch[2] &= hasWorked(c,'F')
                        ch[3] &= (numOfDaysTog(d,a)==3-1)
                        ch[4] &= (numOfDaysTog(e,a)==1)

    if cnt==0: ch = [False]*5
    s = ""
    for c in ch:
        if c : s+=" %s"%(ch.index(c)+1)
    print(u"∴%s"%s)
    print("Runtime : %.3f [sec]"%(time()-tm))   # Timer Stop & Disp

if __name__ == '__main__':
    main()

●実行結果

[1]
 MTWTF
Aoxoxo
Bxoxoo
Coooox
Doxoxo
Exoxoo

∴ 5
Runtime : 0.125 [sec]

※参考URL
UMTWRFS
判断推理の出勤簿の問題をJavaで解いてみた。
知恵袋で見つけた判断推理の出勤簿の問題をPythonで解いてみた。(2)