今日はなにの日。

気になったこと勉強になったことのメモ。

今日は、灘中の入試Pythonで解いてみたの日。

とある日

www.youtube.com

この動画を見てて、この問題とかってプログラムで解くとどうなるんだろうって・・・。

よし、やってみよう。

選ばれた問題

プログラムで解くと言っても、解ける問題と解けない問題はあると思います。

なので、例の動画で解けそうな問題を選択。

f:id:Updraft:20200717212942p:plain

例の動画では、灘入試問題を使用していてそれを改題している。

改題前の内容がこれである。

A,B,C,D,E,F,G,Hはどの2つも異なる2から9までの数字です。
3桁の整数ABCとDEFを足すと4桁の整数10GHになり、
この足し算で繰り上がりは百の位から千の位にだけあるとき、GとHの和は①です。
さらにこのとき、AがDより大きいとすると、
ABCとして考えられる3桁の整数は全部で②個あります。

今回は、動画で見た改題した問題を解いていこうと思います。

実行環境

  • Python3.8

 

いざプログラム作成

まず、考えたのがAからHに2から9までの、すべての組み合わせを作成しその配列が条件に合うかどうかを判定して行く方向性を考えました。

下準備

条件を判定するための配列を用意する。

1.2~9全ての組み合わせ作成

下記の感じの配列を生成したい。

[2,3,4,5,6,7,8,9],
[3,2,4,5,6,7,8,9],
[3,4,2,5,6,7,8,9]...

ただ、人力でやるのはしんどいので。

itertoolsライブラリーを使用すれば同様のことがすぐできる。

import itertools

def CreateList():
    number = list(range(2,10,1))
    for i in itertools.permutations(number):
        print(i)

これを実行すると全ての組み合わせを印字されます。

その数40320でした。

計算方法が8個の数字の組み合わせなので8! = 40320

※ただこれには、重複が含まれます。

2.A~Hの配列作成

3.で1.で作成したものと合わせて辞書配列を作成するためのKeyとなるA~Hの配列を生成したい。

alphabet = ["A","B"...]

と、書いていくのもいいのですが、めんどくさいので・・・。

alphabet_key = [chr(i) for i in range(65, 65+8)]

>>>['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

上記の一行でかんたんに作成可能。

これは、知らなくてJavaだとchar型で簡単に作成できたなと思い、Pythonでもあるのかとググってみたら上記のプログラムを発見した。

これは、新発見だった。

3.配列を合わせてA~Hの辞書配列作成

1.と2.をあわせてAからHをKeyで値を管理するため下記の辞書配列を作成したい。

{'A': 2, 'B': 3, 'C': 4, 'D': 5, 'E': 6, 'F': 7, 'G': 8, 'H': 9} 

一つ一つfor文でやっていってもいいのですが、芸がないので。

ぱぱっとできる方法を検索。

def CreateList():
    number = list(range(2,10,1))
    result = []
    alphabet_key = [chr(i) for i in range(65, 65+8)]
    for i in itertools.permutations(number):
        alphabet_dict = dict(zip(alphabet_key,i))
        result.append(alphabet_dict)
    return result

alphabet_dict = dict(zip(alphabet_key,i))

これがその役目を果たしている。

zip関数を使用すればList同士を結合できる。

dict関数でそれを辞書配列に変換する。

※途中まで1.で作成したListだけで値を管理してたのですが、indexのミスが多発したので辞書配列を作成しました。 なので実際に作成した順番とは異なります。

実際に起ったindexミス

AとGのindexの数値を取り出そうとしたとき。

Aはindexが2番地、Gはindexが何番だっけ・・。

アルファベット順で数えてたら・・、7番か

違う。

配列のindexは0から始まるので、アルファベット順とは違うため。

繰り上がりなし判定

繰り上がりは百の位から千の位の部分でのみでしか起きない。

言い換えれば、BとE、CとFを足した結果は9以下になる。

足した結果を判定

値を取り出して計算するのもいいのですが、処理をわかりやすくするため関数として作成して呼び出す形を取ります。

lambdaでもいいかなと思いましたが横に長くなるのあまり好ましくないので・・・。

def Addition(top,bottom):
    return True if  top + bottom <= 9 else False

三項演算子を使用して簡単に判定。

呼び足して判定

def NotMoveUpCheck(check_list):
    c,f,b,e = check_list["C"],check_list["F"],check_list["B"],check_list["E"]
    if Addition(c,f) and Addition(b,e):
        return True
    return False

該当の値を取り出して、先程作った関数を呼び出す。

※早期リターンを採用している。

繰り上がりあり判定

繰り上がりは百の位から千の位の部分で起きるのでそれを判定する。

正確に言うと、AとDを合わせると10となる組み合わせを判定。

先ほどと似た感じで作成していきます。

足して10判定

def JustTen(top,bottom):
    return True if top + bottom == 10 else False

9以下を判定したときと同じで、三項演算子を使用して判定している。

呼び出して判定

def MoveUpCheck(check_list):
    a,d = check_list["A"],check_list["D"]
    if JustTen(a,d):
        return True
    return False

やってることはシンプル。

足した結果一致判定

C+F → H

B+E → G

上記の条件を判定していく。

足して一致判定

def MatchTwo(top,middle,bottom):
    return True if top + middle == bottom else False

それぞれを判定

def AdditionCheckMatch(check_list):
    # C+F → H
    # B+E → G
    c,f,h = check_list["C"],check_list["F"],check_list["H"]
    b,e,g = check_list["B"],check_list["E"],check_list["G"]
    if MatchTwo(c,f,h) and MatchTwo(b,e,g):
        return True
    return False

それぞれの値をもとに、関数呼び出して計算判定。

全ての組み合わせ呼び出す

def Main():
    create_data = CreateList()
    result = DoubleCheck(create_data)
    print(result[0]["G"]+result[0]["H"])

if __name__ == "__main__":
    Main()

これで、結果が印字される。

17となれば成功です。

全体のプログラム

import itertools
from typing import Match
def CreateList():
    number = list(range(2,10,1))
    result = []
    alphabet_key = [chr(i) for i in range(65, 65+8)]
    for i in itertools.permutations(number):
        alphabet_dict = dict(zip(alphabet_key,i))
        result.append(alphabet_dict)
    return result

def DoubleCheck(check_list):
    result = []
    for i in check_list:
        if AllListCheck(i) and AdditionCheckMatch(i):
            result.append(i)
    return result

def NotMoveUpCheck(check_list):
    c,f,b,e = check_list["C"],check_list["F"],check_list["B"],check_list["E"]
    if Addition(c,f) and Addition(b,e):
        return True
    return False

def Addition(top,bottom):
    return True if  top + bottom <= 9 else False

def MoveUpCheck(check_list):
    a,d = check_list["A"],check_list["D"]
    if JustTen(a,d):
        return True
    return False

def JustTen(top,bottom):
    return True if top + bottom == 10 else False

def AllListCheck(check_list):
    if NotMoveUpCheck(check_list) and MoveUpCheck(check_list):
        return True
    return False

def AdditionCheckMatch(check_list):
    # C+F → H
    # B+E → G
    c,f,h = check_list["C"],check_list["F"],check_list["H"]
    b,e,g = check_list["B"],check_list["E"],check_list["G"]
    if MatchTwo(c,f,h) and MatchTwo(b,e,g):
        return True
    return False

def MatchTwo(top,middle,bottom):
    return True if top + middle == bottom else False

def Main():
    create_data = CreateList()
    result = DoubleCheck(create_data)
    print(result[0]["G"]+result[0]["H"])
if __name__ == "__main__":
    Main()

全体の作成時間は一時間ぐらいでした。

一つの問題で一時間かけてたら入試としては不合格になりますね。

もっと、いい方法があるとは思いますがそこは今後の課題ということで。

他にも、違う問題を解いていきたい。