問題文
以下の問に答えよ。
- 和が $30$ になる2つの自然数からなる順列の総数を求めよ。
- 和が $30$ になる3つの自然数からなる順列の総数を求めよ。
- 和が $30$ になる3つの自然数からなる組合せの総数を求めよ。
(2020 神戸大学 理系第3問 文系第3問)
- $29$ 通り
- $406$ 通り
- $75$ 通り
※ この答えは学校側が公表したものではありません。個人が作成した非公式の答えです。
コード
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib.gridspec as gridspec
from matplotlib.patches import PathPatch
from matplotlib.textpath import TextPath
from matplotlib.font_manager import FontProperties
#紙の準備
fig = plt.figure()
fig.suptitle("2020神戸大数学 理系第3問 文系第3問",
color="0.5",ha="right",x=0.95,y=0.95,zorder=-1)
fig.subplots_adjust(left=0.04,right=0.96,top=0.8,bottom=0.1,wspace=1.0,hspace=0.0)
gs = gridspec.GridSpec(2,10)
ax0 = fig.add_subplot(gs[0,:])
ax0.set_xlim(0,800)
ax0.set_ylim(0,220)
ax0.set_aspect("equal")
ax0.axis("off")
#フォント辞書たち
counterdic={
"clip_on" : True,
"fontsize" : 18,
"fontfamily" : "fantasy",
"verticalalignment" : "center",
"horizontalalignment" : "center"
}
commentdic={
"ha" : "center",
"va" : "center",
"size" : 20,
"color" : "white",
"zorder" : 10,
"fontfamily": "Meiryo",
"linespacing" : 2,
}
commentbgdic={
"facecolor" : "black",
"pad" : 300,
}
#減らず口たち
msg1 = "足して30になる\n3つの数の組合せは?"
msg2 = "(答)\n75通り"
msg3 = "お魚の骨をとるより\nメンドくさかったです\n┐(´д`)┌"
comment = fig.text(0.5,0.5,msg1,
fontdict=commentdic,bbox=commentbgdic)
#お気に入りのイージング関数
def easing(x):
if x<0.5:
return 2*x**2
else:
return 1-(-2*x+2)**2/2
#文字を刻む
def add_text(x,y,text):
if type(text)==int:
text = "{:>2}".format(text)
fp = FontProperties(family="fantasy")
path = TextPath((x,y),text,prop=fp)
patch = PathPatch(path,color="k")
ax0.add_patch(patch)
#足し算を刻む
def add_case(box_x,box_y,a,b,c):
add_text(box_x, box_y,a)
add_text(box_x+16,box_y,"+")
add_text(box_x+24,box_y,b)
add_text(box_x+40,box_y,"+")
add_text(box_x+48,box_y,c)
#最初の数に注目して場合分けし、全通りを刻む
for a in range(1,11):
exec("ax{}=fig.add_subplot(gs[1,{}])".format(a,a-1))
exec("ax{}.set_title(str(a)+\" ―\",fontfamily=\"fantasy\",color=\"0.5\")".format(a))
exec("ax{}.set_xlim( 0,100)".format(a))
exec("ax{}.set_ylim(-100,0)".format(a))
exec("ax{}.xaxis.set_ticks([])".format(a))
exec("ax{}.yaxis.set_ticks([])".format(a))
exec("ax{}.set_aspect(\"equal\")".format(a))
exec("ax{}.text(50,-60,str(0),fontdict=counterdic)".format(a))
fig.text(0.04+0.92/38*(4*a-2),0.21,"個",color="0.5",ha="right")
if a<10:
fig.text(0.04+0.92/38*(4*a-1),0.27,"+",fontdict=counterdic)
else:
answer=fig.text(0.9,0.12,"= 75",fontdict=counterdic,alpha=0,size=24)
for b in range(a,(30-a)//2+1):
c = 30-a-b
add_case(80*a-70,220-15*b,a,b,c)
exec("ax{}.text(50,-60-(b-a+1)*100,str(b-a+1),fontdict=counterdic)".format(a))
#一つ一つにズームする
def zoom_in(a,t):
k = t/30
if k<=1:
k = easing(k)
left = (80*a-80)*k
top = 220-15*(a-1)*k
width = 800-720*k
height = width/80*22
ax0.set_xlim(left,left+width)
ax0.set_ylim(top-height,top)
exec("ax{}.set_ylim(-100-100*k,-100*k)".format(a))
#個数を数えていく
def count(a,t):
d = (30-a)//2-a
k = t/(15*d+1)
if k<=1:
k = easing(k)
down = (15*d+1)*k
ax0.set_xlim(80*a-80,80*a)
ax0.set_ylim(213-15*a-down,235-15*a-down)
down = 100*d*k
exec("ax{}.set_ylim(-200-down,-100-down)".format(a))
#全体に戻る
def zoom_out(a,t):
k = t/30
if k<=1:
k = easing(k)
left = (80*a-80)*(1-k)
top = 220-(15*((30-a)//2-1)+1)*(1-k)
width = 800-720*(1-k)
height = width/80*22
ax0.set_xlim(left,left+width)
ax0.set_ylim(top-height,top)
#それぞれの場合において
def section(a,t):
n = (30-a)//2-a+1
if t<45:
zoom_in(a,t)
elif t<45+15*n:
count(a,t-40)
else:
zoom_out(a,t-45-15*n)
#場合ごとにフェーズを作る
phases = np.array([0])
for a in range(1,11):
n = (30-a)//2-a+1
t = phases[-1]+90+15*n
phases = np.append(phases,t)
#動画本番
def update(i):
if i<50:
pass
elif i==50:
comment.set_visible(False)
elif i<75:
pass
elif i<2100:
k = i-75
section_end = phases[phases>k][0]
a = list(phases).index(section_end)
t = k - phases[a-1]
section(a,t)
elif i<2150:
k = i-2100
alpha = max(min(k/25,1),0)
alpha = easing(alpha)
answer.set_alpha(alpha)
elif i==2150:
comment.set_text(msg2)
comment.set_visible(True)
elif i==2200:
comment.set_text(msg3)
mov = ani.FuncAnimation(fig,update,2250,interval=100)
plt.show()