こんにちは、現役京大生ブロガーのゲーテ(@goethe_kyodai)です。
普通に解いても面白くないのでプログラミング(Python)で2018年の理系の京大数学を解いてみました。
プログラミングで解くことに重きを置き、厳密な議論は飛ばしていて模範解答とは程遠い解答となっているので高校生のみんなは参考にしないように。
使用言語:Python2系
使用ライブラリ:Sympy,Numpy,Math,matplotlib
Sympyの使い方はこちらを参考にしました。
はてなブログにコードを埋め込むのはこちらを参考にしました。
目次
問題1
(1)
とからyを消去して整理して、
・・・(1)
を得る。
上式の判別式をdiscriminant()で求めると、
となる。
これをsolve()でについて解くと、
となる。
これをsubs()で(1)に代入してsolve()でxについて解くと、
を得る。
これをにsubs()で代入して、
を得る。
これらが答えの接点の座標である。
まとめると答えは
(2)
まず先ほど求めた接点をと置きます。
そしてsolve()でこれらの連立方程式をx、yについて解くと、
となります。
これを条件(1)の不等式を等式に置き換えた、にsubs()で代入してsolve()でyについて解くと、
を得られます。
このyと閉区間 [-1,1] の範囲のxを使って、matplotlibで図示したのが下です。
本来の条件(1)は不等式なので上図の円に囲まれた部分が答えです。(本来はa,b,cの条件から除外する点があるがめんどくさいので省略)
from sympy import *
from matplotlib import pyplot as plt
import numpy as np
x = Symbol('x')
y = Symbol('y')
a = Symbol('a')
b = Symbol('b')
c = Symbol('c')
expr1 = a*x**2
expr2 = b*(x-1)**2 + c
expr3 = expand(expr2 - expr1)
D = Poly(expr3).discriminant()
b_1 = solve(D,b)[0]
expr4 = expr3.subs([(b,b_1)])
contact_x = solve(expr4,x)[0]
contact_y = a*contact_x**2
print("接点の座標は ({},{})".format(contact_x,contact_y))
eq1 = x - contact_x
eq2 = y - contact_y
[a_1,c_1] = solve([eq1,eq2],[a,c])[0]
expr5 = 1 + c**2 - 2*a_1
expr6 = sympify(expr5.subs([(a,a_1),(c,c_1)]))
point_y = solve(expr6,y)
X = np.linspace(-1,1,100)
Y = []
for point_x in X:
Y.append(point_y[0].subs(x,point_x))
plt.plot(X,Y,'r')
Y = []
for point_x in X:
Y.append(point_y[1].subs(x,point_x))
plt.plot(X,Y,'r')
plt.xlabel("x-label")
plt.ylabel("y-label")
plt.show()
問題2
と置きます。
因数分解できなさそうなので代入して構造を調べました。
その前に整数nじゃ範囲が広すぎるので、が素数になり得るnの範囲を調べておきましょう。
と置きます。
これをmatplotlibのpyplotで図示すると下のようになります。
見た感じとなるのはですね。これで調べる範囲をに限定できました。
では実際に代入して素数かどうかの判定をとりあえずn = -3 ~ 20 までしてきます。
プログラムで実際に代入した結果がこちら↓
n = -3,f(n) = 3で、「f(n)が素数である」はTrue
n = -2,f(n) = 15で、「f(n)が素数である」はFalse
n = -1,f(n) = 15で、「f(n)が素数である」はFalse
n = 0,f(n) = 9で、「f(n)が素数である」はFalse
n = 1,f(n) = 3で、「f(n)が素数である」はTrue
n = 2,f(n) = 3で、「f(n)が素数である」はTrue
n = 3,f(n) = 15で、「f(n)が素数である」はFalse
n = 4,f(n) = 45で、「f(n)が素数である」はFalse
n = 5,f(n) = 99で、「f(n)が素数である」はFalse
n = 6,f(n) = 183で、「f(n)が素数である」はFalse
n = 7,f(n) = 303で、「f(n)が素数である」はFalse
n = 8,f(n) = 465で、「f(n)が素数である」はFalse
n = 9,f(n) = 675で、「f(n)が素数である」はFalse
n = 10,f(n) = 939で、「f(n)が素数である」はFalse
n = 11,f(n) = 1263で、「f(n)が素数である」はFalse
n = 12,f(n) = 1653で、「f(n)が素数である」はFalse
n = 13,f(n) = 2115で、「f(n)が素数である」はFalse
n = 14,f(n) = 2655で、「f(n)が素数である」はFalse
n = 15,f(n) = 3279で、「f(n)が素数である」はFalse
n = 16,f(n) = 3993で、「f(n)が素数である」はFalse
n = 17,f(n) = 4803で、「f(n)が素数である」はFalse
n = 18,f(n) = 5715で、「f(n)が素数である」はFalse
n = 19,f(n) = 6735で、「f(n)が素数である」はFalse
n = 20,f(n) = 7869で、「f(n)が素数である」はFalse
どうやらではf(n)は素数にならないっぽいので、n=3m,3m+1,3m+2(m は 整数で1以上)と置いてそれを証明してみます。
とりあえず代入してみます。
f(3m) =
f(3m+1) =
f(3m+2) =
いい感じに3 (多項式)になってますね。
あとはf(3m)、f(3m+1)、f(3m+1)を3で割った、、が2以上の整数になっていれば、f(3m)、f(3m+1)、f(3m+1)が合成数になるので素数にならないことを証明できます。
それをmatplotlibのpyplotで図示して目視で確認しましょう。
それぞれ2以上になってますね。
以上より答えはn = -3、1、2で解けました。
from matplotlib import pyplot as plt
from sympy import *
import numpy as np
import math
def is_prime(x):
if x < 2: return False
if x == 2 or x == 3 or x == 5: return True
if x % 2 == 0 or x % 3 == 0 or x % 5 == 0: return False
prime = 7
step = 4
while prime <= math.sqrt(x):
if x % prime == 0: return False
prime += step
step = 6 - step
return True
x = Symbol('x')
n = Symbol('n')
m = Symbol('m')
expr1 = x**3 - 7 * x +9
X = np.linspace(-4,4,100)
Y = X**3 - 7 * X + 9
plt.plot(X,Y,label="g(x)")
plt.plot([-4,4],[0,0],label="g(x) = 0")
plt.plot([-3,-3],[-30,40],label="x = -3")
plt.title("g(x) = $x^3 - 7x + 9$")
plt.xlabel("x-LABEL")
plt.ylabel("g(x)-LABEL")
plt.legend()
plt.show()
a = -3
for i in range(24):
solution = expr1.subs(x,a)
isPrime = is_prime(solution)
print("n = {},f(n) = {}で、「f(n)が素数である」は{}".format(a,solution,isPrime))
a += 1
print("\n")
b = [3*m,3*m+1,3*m+2]
for bb in b:
expr2 = expand(expr1.subs(x,bb))
print("n = {},f(n) = {}".format(bb,expr2))
print("\n")
point_x = np.linspace(-3,3,100)
for bb in b:
expr3 = expand(expr1.subs(x,bb))/3
print("n = {},f(n)/3 = {}".format(bb,expr3))
point_y = []
for point in point_x:
point_y.append(expr3.subs(m,point))
plt.plot(point_x,point_y,label = "{}".format(expr3))
plt.plot([-3,3],[2,2],label = "f/3 = 2")
plt.plot([1,1],[-400,400],label = "m = 1")
plt.xlabel("m-label")
plt.title("$f(3m)/3,f(3m+1)/3,f(3m+2)/3$")
plt.legend()
plt.show()
問題3
変数を導入して、条件から上図のように角を表します。
外接円の半径が1であることと正弦定理より
よって
AB =
BC =
CD =
DA =
と表せます。
これらを使ってkは
k =
と表せます。(ここまでプログラミング登場なし)
入試問題的には最大値をで表せばいいのですが、プログラミングを駆使して解きたいので0 < を満たす任意の実数の入力に対して、線形探索で最大値を出すプログラムを書きました。
そのプログラムのアルゴリズムは
1:を受け取る
2:0 < < の範囲で任意個に均等に分けたを用意する。
3:さっき分けたを小さい方から順にと共にkに代入して計算し、kの最大値を線形探索で求める
線形探索なので計算量はO(n)(n は を分割した数)です。
from sympy import *
import math
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
a = Symbol('a')
b = Symbol('b')
AB = 2 * sin(pi - (a+b))
BC = 2 * sin(b)
CD = 2 * sin(a-b)
DA = 2 * sin(b)
k = expand(AB*BC*CD*DA)
constant_a = math.pi/4.0
roop = 10000
B = np.linspace(0,constant_a,roop+2)
B = np.delete(B,0,axis=None)
B = np.delete(B,-1,axis=None)
max_k = -16
max_b = B[0]
k = k.subs([(a,constant_a)])
for bb in B:
tmp = k.subs([(b,bb)])
if tmp > max_k:
max_b = bb
max_k = tmp
print("alpha = {},theta = {}の時、kの最大値は{}".format(constant_a,max_b,max_k))
問題4
解法1
となる確率をP( = 1)とおく。
P( = 1 ) = です。
[全ての ]はで、[ = 1となるの数] ]は再帰を使った全探索で求められます。
計算量がO()になってしまいますが、計算時間の制限がなければ任意の入力nに対して一応この解法で解けます。
from sympy import *
import math
expr1 = -0.5 + sqrt(3)*I/2
n = 10
count = 0
def calcz(z,depth):
global n
global count
if depth == n:
if z == 1:
count +=1
else:
front = expand(expr1*z)
calcz(front,depth+1)
back = expand(conjugate(z))
calcz(back,depth+1)
calcz(expr1,1)
calcz(1,1)
prob = (count + 0.0)/2**n
print("n = {},probability = {}".format(n,prob))
解法2
解法1は計算量が大きすぎるので速い方法で解いてみます。
a = 1、b = 、c = と置きます。
がa、b、cとなる確率を、、と置きます。
それらを用いた以下の漸化式が成り立ちます。
+ = 2
+ = 2
=
A = 、B = 、とすると上の漸化式は
A = B
と表せます。
式変形すると
=
と表せます。C = と置くと
= C
となるので
=
と表せます。
をプログラミングの計算力を使ってCをn-1回掛けて求めてもいいですが、計算量がO()になってしまうので対角化しましょう。
D = となるようにCを対角化します。この時、Cの固有値をdiagnolize()で求めて、とすると、
= =
と表せて計算量がO(n)ですみます。
この とを使ってを求められます。
このが求める確率P( = 1)です。
from sympy import *
import math
n = Symbol('n')
A = Matrix([[1,0,1],[1,0,1],[0,1,0]])
B = Matrix([[2,0,0],[0,2,0],[0,0,1]])
C = B.inv()*A
(P,D) = C.diagonalize()
DD = zeros(3)
i = 0
while(i <= 3*3 - 1):
DD[i] = D[i]**n
i += 3 + 1
x_1 = Matrix([0.5,0.5,0])
x_n = P*DD*P.inv()* x_1
print("a_n= {}".format(x_n[0]))
問題5
(1)
を普通に求めると、
これらをdiff()を使ってtで微分すると答えを出せます。
答えは
です。
(2)
、と表せます。
integrate()で積分してとを求めてlimit()でを求めようと試みましたが、、、
はすぐ求められました、の式がゴツすぎるせいか中々結果を吐き出してくれませんでした。
なので式を簡単化します。
(1)で求めた導関数をよく見ると、 = の関係になってます。
これを使うとと表せ、さらにこれを使ってを簡単化して
と表せます。(Sympyのcancel()やsimplify()を使って = からここまで簡単化できると思ったんですが中々できなくて手で計算しました。)
このように式変形してlim()でやっと解けるようになります。
from sympy import *
import math
t = Symbol('t')
r = Symbol('r')
u = t + 1/sqrt(t**2 + 1)
v = log(t) - t/sqrt(t**2 + 1)
print("(u(t),v(t)) = ({}, {})\n".format(u,v))
du = diff(u,t)
dv = diff(v,t)
print("(du/dt,dv/dt) = ({}, {})\n".format(du,dv))
expr1 = 1/(t**2+1)
expr2 = integrate(expr1,t).subs(t,1) - integrate(expr1,t).subs(t,r)
solution = limit(expr2,r,0)
print("lim(L1(r) - L2(r)) = {}".format(solution))
問題6
(1)
まずD= (0,0,0)、A=()、B=()、C= ()と置きます。
その座標を使って計算したPQ•ABをLと置きます。PQとABが垂直になることを示せばいいのでL=0を示せばいいですね。
条件AC = BD、AD = BCをsolve()で解いてで表して、それらをLにsubs()してsymplify()とexpand()してもLが0にならなかったので方針を変更しました。
条件AC = BD、AD = BCを二乗したを辺々足してexpand()で展開すると、
になります。左辺をMと置きます。
Lをexpand()で展開すると、
となります。
二つの式を目視で比べると、L = - 0.25 Mとなっていることがわかるので、L = 0となり、証明できました。(結局目視)
from sympy import *
a1 = Symbol('a1')
a2 = Symbol('a2')
a3 = Symbol('a3')
b1 = Symbol('b1')
b2 = Symbol('b2')
b3 = Symbol('b3')
c1 = Symbol('c1')
c2 = Symbol('c2')
c3 = Symbol('c3')
BA = Matrix([a1,a2,a3])
BD = Matrix([b1,b2,b3])
BC = Matrix([c1,c2,c3])
AC = BC - BA
AD = BD - BA
PA = 0.5*BA
AQ = 0.5*AD + 0.5*AC
PQ = PA + AQ
expr1 = AC.transpose()*AC - BD.transpose()*BD
expr2 = AD.transpose()*AD - BC.transpose()*BC
M = expr1 + expr2
print("M = {}".format(M[0]))
L = PQ.transpose()*BA
print("L = {}".format(L[0]))
(2)
分からん。
PQを通る平面の方程式を出して、どの線分に交わるかで場合分けして、分けられた図形の体積を導出して比べたら解けそうだけどめんどくさいのでやってません。
いい感じにプログラミングで解ける方法思いついたらコメントで教えてください。
感想
最初はなんでも計算機の計算能力でゴリ押しすれば京大数学なんて解けるだろ!と思ってたんですが全然そんなことありませんでした。解けるように上手く式変形するのは人間の手でやるしかなさそうです。
どんな数学の問題を特にしても、計算機が得意なところと人間が得意なところを分担できる程度の計算機の理解が必要 だとも思いました。あと計算機が解ける形にするために数学はやっぱ大事だなって改めて思いました。数学勉強頑張ります。
参考書
平岡 和幸,堀 玄 オーム社 2004-10-01
行列式、固有値、固有ベクトルなど線形代数の基本的な内容を図で直感的に理解できる良本です。