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

 以前、Javaで解いた判断推理の出勤簿の問題Pythonで解いてみました。と、いうより翻訳してみました。(^_^;
 どうも、同じものを含む順列set(itertools.permutations())を使うと遅いようなので、前回と同様、itertools.product()でループを回してみました。(^_^;
 それから、結果の表示をJava版に合わせて全角にしてみました。(^_^;
 ちなみに、ループをeから逆に始めると、倍速近く速くなります。o(^-^)o

● AttendanceBook2.py

# coding: UTF-8
# AttendanceBook2.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

# aの出勤表laからc曜日に働いたか調べる
# 'UMTWRFS': '日月火水木金土'
def hasWorked(la, c):
    WD = 'UMTWRFS'
    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 = u'ABCDE'
    print(u' 日月火水木金土')
    for i in range(n):
        s = NAME[i]+''.join(lst[i])
        print(s.replace('o',u'○').replace('x',u'×'))
    print('')

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

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

    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]
 日月火水木金土
A×○×○×○×
B○○×○×○○
C○○×××○○
D××○○○××
E○○×××○○

∴ 3
Runtime : 0.357 [sec]

※参考URL
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1124852786
UMTWRFS
判断推理の出勤簿の問題をJavaで解いてみた。
知恵袋で見つけた判断推理の出勤簿の問題をPythonで解いてみた。