問題文
座標平面上に8本の直線 $$x=a\,(a=1,2,3,4),\quad y=b\,(b=1,2,3,4)$$ がある。以下、16個の点 $$(a,b)\quad(a=1,2,3,4,\quad b=1,2,3,4)$$ から異なる5個の点を選ぶことを考える。
次の条件を満たす5個の点の選び方は何通りあるか。
上の8本の直線のうち、選んだ点を1個も含まないものがちょうど2本ある。
次の条件を満たす5個の点の選び方は何通りあるか。
上の8本の直線のうち、いずれも選んだ点を少なくとも1個も含む。
(2020 東京大学 文系第2問)
- $1824$ 通り
- $432$ 通り
※ この答えは学校側が公表したものではありません。個人が作成した非公式の答えです。
コード
import itertools
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.lines as lines
import matplotlib.animation as ani
#紙の準備
fig = plt.figure(facecolor="wheat")
fig.suptitle("2020東大数学 文系第2問",
color="0.5",x=0.97,y=0.05,
ha="right",va="center")
ax = fig.add_subplot(111)
ax.set_xlim(0.5,4.5)
ax.set_ylim(0.5,4.5)
ax.set_aspect("equal")
ax.axis("off")
#碁盤の目を描く
for i in range(1,5):
exec('H{},=ax.plot([1,4],[i,i],color="k",zorder=-10)'.format(i))
exec('V{},=ax.plot([i,i],[1,4],color="k",zorder=-10)'.format(i))
#各マス目の番号(16進数)
l = ["0","1","2","3",
"4","5","6","7",
"8","9","a","b",
"c","d","e","f"]
#16進数を座標に変換
def hex2ab(v):
A = []
B = []
for i in range(5):
n = int(v[i],16)
a = 1+n%4
b = 4-n//4
A.append(a)
B.append(b)
return A,B
#(1)の全通りを列挙
c_q1 = []
for v in itertools.combinations(l,5):
A,B = hex2ab(v)
condition =\
len(set(A))+len(set(B))==6
if condition:
c_q1.append(v)
#(2)の全通りを列挙
c_q2 = []
for v in itertools.combinations(l,5):
A,B = hex2ab(v)
condition =\
len(set(A))+len(set(B))==8
if condition:
c_q2.append(v)
#ばらばらに置かれた碁石
Title = ax.text(2.0,4.6,"n =",color="saddlebrown",
fontsize=20,fontfamily="fantasy")
Count = ax.text(2.5,4.6,"{:>4}".format(0),color="saddlebrown",
fontsize=20,fontfamily="fantasy")
Fives = ax.scatter([-0.1,0.4,4.2,4.5,4.7],[1.7,2.6,3.4,1.3,2.7],
c="k",s=1800,clip_on=False)
#減らずグチたち
commentdic={
"ha" : "center",
"va" : "center",
"size" : 20,
"color" : "white",
"zorder" : 10,
"fontfamily": "Meiryo",
"linespacing" : 2,
}
commentbgdic={
"facecolor" : "black",
"pad" : 300,
}
msg_opening1 = "絶対に\n負けられない 戦いが\n\nここにはある"
msg_opening2 = "これから始めるのは\n4行$\\,\\times$4列の碁盤の目に\n5個の碁石を並べていく\n無味乾燥なゲームである"
msg_before_q1 = "(1)\n碁石の置かれていない線が\nちょうど2本ある場合は?"
msg_answer_q1 = "(1) の答え\n{} 通り".format(len(c_q1))
msg_before_q2 = "(2)\n碁石の置かれていない線が\n1本もない場合は?"
msg_answer_q2 = "(2) の答え\n{} 通り".format(len(c_q2))
msg_ending1 = "ここまで見てくださった\nあなたは\nものすごい忍耐力\nの持ち主です!"
msg_ending2 = "きっと\n良いことがあるでしょう\n\nGOOD LUCK !!"
comment = fig.text(0.5,0.5,"",
fontdict=commentdic,bbox=commentbgdic)
#訂正線
strike_through = lines.Line2D([0.29,0.29],[0.56,0.56],
color="w",linewidth=2.5,zorder=11)
fig.add_artist(strike_through)
txt_opening1 = fig.text(0.43,0.47,"数え切る",
zorder=11,alpha=0,fontdict=commentdic)
#ひとつひとつの場合を見せる
def show_case(k,v):
A,B = hex2ab(v)
Fives.set_offsets(list(zip(A,B)))
str_count = "{:>4}".format(k+1)
Count.set_text(str_count)
return A,B
#問題(1)
def q1(t):
if t==0:
comment.set_text(msg_before_q1)
comment.set_visible(True)
if t==40:
comment.set_visible(False)
k = min(max(t-80,0),len(c_q1)-1)
v = c_q1[k]
A,B = show_case(k,v)
for i in range(1,5):
if i in A:
exec('V{}.set_linestyle("solid")'.format(i))
else:
exec('V{}.set_linestyle("dashed")'.format(i))
if i in B:
exec('H{}.set_linestyle("solid")'.format(i))
else:
exec('H{}.set_linestyle("dashed")'.format(i))
if t==1950:
comment.set_text(msg_answer_q1)
comment.set_visible(True)
#問題(2)
def q2(t):
if t==0:
comment.set_text(msg_before_q2)
for i in range(1,5):
exec('V{}.set_linestyle("solid")'.format(i))
exec('H{}.set_linestyle("solid")'.format(i))
if t==40:
comment.set_visible(False)
k = min(max(t-80,0),len(c_q2)-1)
v = c_q2[k]
show_case(k,v)
if t==550:
comment.set_text(msg_answer_q2)
comment.set_visible(True)
#お気に入りのイージング関数
def easing(x):
return -(np.cos(np.pi*x)-1)/2
#オープニング
def opening(t):
if t==0:
comment.set_text(msg_opening1)
if t>=20 and t<=40:
k = easing((t-20)/20)
strike_through.set_xdata([0.29,0.29+0.27*k])
if t>=60 and t<=80:
k = easing((t-60)/20)
txt_opening1.set_alpha(k)
if t==120:
comment.set_text(msg_opening2)
for obj in [strike_through,txt_opening1]:
obj.set_visible(False)
if t==170:
comment.set_visible(False)
#エンディング
def ending(t):
if t==0:
comment.set_text(msg_ending1)
if t==50:
comment.set_text(msg_ending2)
#上演
def update(i):
if i<220:
opening(i)
elif i<2220:
q1(i-220)
elif i<2820:
q2(i-2220)
else:
ending(i-2820)
mov = ani.FuncAnimation(fig,update,2900,interval=100)
plt.show()