漢字プリント 数学プリント
問題文
縦4個、横4個のマス目のそれぞれに1、2、3、4の数字を入れていく。このマス目の横の並びを行といい、縦の並びを列という。どの行にも、どの列にも同じ数字が1回しか現れない入れ方は何通りあるか求めよ。下図はこのような入れ方の1例である。
図
(2020 京都大学 理系第5問 文系第5問)
$$576$$
※ この答えは学校側が公表したものではありません。個人が作成した非公式の答えです。
コード
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as ani

fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(0,5)
ax.set_ylim(0,5)
ax.set_aspect("equal")
ax.axis("off")
ax.grid()
ax.set_title("2020京大数学 理系第5問 文系第5問",pad=15)

#順列でシャッフル
def shuffle(mother):
    
    oldlady = ""
    oldladies = [oldlady]

    for digit in range(len(mother)):
        newladies = []
        
        for oldlady in oldladies:
            for m in mother:
                
                admission = m not in oldlady
                
                if admission:
                    newlady = oldlady + m
                    newladies.append(newlady)
    
        oldladies = newladies
    
    return oldladies

#新しく追加できる行
def get_newrows(k,X):
    
    rows = []
    
    for str_row in shuffle("1234".replace(X[k,0],"")):
        row = np.array(list(str_row))
        
        overlap = False
        for i in range(X[:k,1:].shape[0]):
            if np.any(row==X[i,1:]):
                overlap = True
                
        if overlap:
            pass
        else:
            rows.append(row)
    
    return rows

#一つ一つの例をプロット
def show(M,N,X,count):
    
    img = [ax.text(1.8,4.8,'N = {:>3}'.format(count),
                   ha="left",va="center",color="dimgrey",
                   fontsize=18,fontfamily='fantasy',)]
    
    img += [ax.pcolormesh(N,M,X.astype(int),
                         cmap="Pastel1",edgecolors="w",linewidth=4)]
    
    alphas = [0.2,0.2,0.2,0.2]
    alphas[(count-1)%4] = 1.0
    for i in range(4):
        img += ax.plot(1.9+0.4*i,0.2,alpha=alphas[i],marker="o",color="navy")
        for j in range(4):
            img += [ax.text(i+1,j+1,X[j,i],
                    ha="center",va="center",
                    fontsize=24,fontfamily='fantasy',
                    color="grey")]
            
    if count<=4:
        img += [ax.text(1.6,0.2,"1行目と1列目を固定したとき",ha="right",va="center",color="navy")]
        img += [ax.text(2.5,-0.2,"n="+str(count),ha="center",va="center",
                        color="navy",fontsize=16,fontfamily='fantasy',)]
        img += [ax.axvspan(0.5,4.5,0.7,0.9,
                           fill=False,edgecolor="navy",linewidth=4)]
        img += [ax.axhspan(0.5,3.5,0.1,0.3,
                           fill=False,edgecolor="navy",linewidth=4)]
    elif count<=24:
        img += [ax.text(1.6,0.2,"1行目を固定したとき",ha="right",va="center",color="navy")]
        img += [ax.text(2.5,-0.2,"n="+str(count),ha="center",va="center",
                        color="navy",fontsize=16,fontfamily='fantasy',)]
        img += [ax.axvspan(0.5,4.5,0.7,0.9,
                           fill=False,edgecolor="navy",linewidth=4)]
        
    return img

#1行目と1列目を固定
X = np.zeros((4,4),dtype=str)
Xs = []
for str_row in shuffle("1234"):
    X[0,:] = np.array(list(str_row))
    for str_col in shuffle("1234".replace(X[0,0],"")):
        X[1:,0] = np.array(list(str_col))

        for row in get_newrows(1,X):
            X[1,1:] = row
            for row in get_newrows(2,X):
                X[2,1:] = row
                for row in get_newrows(3,X):
                    X[3,1:] = row
                    Xs.append(X.copy())

M,N = np.mgrid[0.5:5.5:1,0.5:5.5:1]

#結果を表示
count = 0
imgs = []
for i,X in enumerate(Xs):
    count += 1
    X = np.flipud(X)
    img = show(M,N,X,count)
    if i < 4:
        for repeat in range(20):
            imgs.append(img)
    elif i < 24:
        for repeat in range(10):
            imgs.append(img)
    elif count == 576:
        for repeat in range(50):
            imgs.append(img)
    else:
        imgs.append(img)
            
mov=ani.ArtistAnimation(fig, imgs, 100)
plt.show()
解説になっているのか?甚だギモンな動画
「高校数学のエアポケット」に戻る