いつもお世話になっております。
土日なので、プログラミングで遊んでいたところ、
アルゴリズムの欠陥がわからず、詰まってしまいました。
2~3時間悩んで進捗が得られないため、助言を求めさせていただきたい次第です。
実現したいこと
iPhoneのパターン認証(線を点でつなぐ認証方式)のパターン数を求めるプログラムを作成したいです。
発生している問題
ググってみると、パターンの総数は「389,112」とのことらしいです。
しかし、自分の実装したコードが出力する回答は「389,488」であり、
若干多い値が出力されます。
どこに考慮漏れがあるのかが、わからないです。
該当のソースコード
Python
1################################################################ 2# iPhoneのパターン認証(線を点でつなぐ認証方式)のパターン数を求めるプログラム 3# 4# それぞれの点は以下の番号で表現する 5# 1 2 3 6# 4 5 6 7# 7 8 9 8################################################################ 9 10 11import itertools 12 13 14def main(): 15 pattern_2 = list(itertools.permutations("123456789", 2)) # 点を2つ繋ぐパターン 16 pattern_3 = list(itertools.permutations("123456789", 3)) # 点を3つ繋ぐパターン 17 pattern_4 = list(itertools.permutations("123456789", 4)) # 点を4つ繋ぐパターン 18 pattern_5 = list(itertools.permutations("123456789", 5)) # 点を5つ繋ぐパターン 19 pattern_6 = list(itertools.permutations("123456789", 6)) # 点を6つ繋ぐパターン 20 pattern_7 = list(itertools.permutations("123456789", 7)) # 点を7つ繋ぐパターン 21 pattern_8 = list(itertools.permutations("123456789", 8)) # 点を8つ繋ぐパターン 22 pattern_9 = list(itertools.permutations("123456789", 9)) # 点を9つ繋ぐパターン 23 24 pattern_as_list = pattern_2 + pattern_3 + pattern_4 + pattern_5 +\ 25 pattern_6 + pattern_7 + pattern_8 + pattern_9 26 27 # 扱いやすいよう、各要素をタプルから文字列に変換 28 pattern_as_str = list(map(lambda x: "".join(x), pattern_as_list)) 29 30 # 1と3の間には2があるので、物理的につなぐことができない(ただし2が通過済みである場合は、つなぐことができる) 31 # 2と8の間には5があるので、物理的につなぐことができない(ただし5が通過済みである場合は、つなぐことができる) 32 # といった具合に、発生しえないパターンを除外する 33 filtered_pattern = list(itertools.filterfalse(is_illegal_pattern, pattern_as_str)) 34 35 print(len(filtered_pattern)) 36 37 38def is_illegal_pattern(pattern: str) -> bool: 39 return ( 40 # 角と角 41 "13" in pattern and not ("2" in pattern[:pattern.find("13")]) 42 or "17" in pattern and not ("4" in pattern[:pattern.find("17")]) 43 or "19" in pattern and not ("5" in pattern[:pattern.find("19")]) 44 or "31" in pattern and not ("2" in pattern[:pattern.find("31")]) 45 or "37" in pattern and not ("5" in pattern[:pattern.find("37")]) 46 or "39" in pattern and not ("6" in pattern[:pattern.find("39")]) 47 or "71" in pattern and not ("4" in pattern[:pattern.find("71")]) 48 or "73" in pattern and not ("5" in pattern[:pattern.find("73")]) 49 or "79" in pattern and not ("8" in pattern[:pattern.find("79")]) 50 or "91" in pattern and not ("5" in pattern[:pattern.find("91")]) 51 or "93" in pattern and not ("6" in pattern[:pattern.find("93")]) 52 or "97" in pattern and not ("8" in pattern[:pattern.find("97")]) 53 or 54 # 辺と辺 55 "28" in pattern and not ("5" in pattern[:pattern.find("28")]) 56 or "46" in pattern and not ("5" in pattern[:pattern.find("46")]) 57 or "64" in pattern and not ("5" in pattern[:pattern.find("64")]) 58 or "82" in pattern and not ("5" in pattern[:pattern.find("82")]) 59 ) 60 61 62if __name__ == "__main__": 63 main() 64
補足
当初は、「ただしXが通過済みである場合は、つなぐことができる」という観点が漏れており、
それに関しては自分で気づくことができました(上記コードにも実装済み)。
回答1件
あなたの回答
tips
プレビュー