はじめまして、MatLaserです!
記念すべきQiita初投稿です、よろしくお願いします!
普段は研究でPythonを使っていますが、最近は様々な技術に興味が出てきてちょっとずつ勉強してます。
本投稿は前々から一度やってみたいと思っていて、GWは時間もあり、良い機会ということで書いてみました。
技術不足・知識不足のため、効率の悪いコーディングや誤った理解等あると思いますが、初心者がアウトプットするために書いているので、暖かい目で見ていただけると幸いです。
なお、問題と解答のpdfはこちらにあるので、適宜参照してください。
本記事でも基本的には解答の解き方に沿ってコーディングしていきます。
第一問
(1) 余弦定理を使うだけですね。
(2) 三点A,B,Cの座標設定をうまくとることで、変数$s$の存在を点Pの$y$座標のみにでき、若干計算が楽になりますね。
それではコーディングしていきます。
# 初期条件
ab = 1
ac = 1
bc = 0.5
import numpy as np
# (1)
# 余弦定理
cos_theta = (ab**2 + ac**2 - bc**2) / (2 * ab * ac)
sin_theta = np.sqrt(1 - cos_theta**2)
print(cos_theta, sin_theta) # 0.875 0.484 = 7/8 (√15)/8
# (2)
# func = AP^2 + BP^2 + CP^2 とする
def func(s):
return 25/32 + 15/64 * ((3 * (s - 2/3)**2) + 2/3)
lis = [] # 変数 s と その時の func の値をタプルとして収納するリスト
# 0<s<1 を 0.01 ずつ変化させ、全探索
for s in np.arange(0,1,0.01):
value = func(s)
lis.append((s, value))
print(lis)
# min_value でソートし、最初の要素を出力
lis_sort = sorted(lis, key=lambda values: values[1])
print(lis_sort[0]) # (s, min_value) = (0.67, 0.9375)
第二問
(1) 素直に直線L、Mの交点を求めて、円Cに代入ですね。
(2) 円Cの中心と直線Lの距離が、円Cの半径(a)よりも小さい時に題意を満たしますね。
(3) (2)と同様、点と直線の距離と円Cの半径を比較することで共有店の個数を求め、あとは愚直に調べるだけですね。
これは(2)の不等号を変えるだけなので省略します。
それではコーディングしていきます。
import sympy
x = sympy.Symbol('x')
y = sympy.Symbol('y')
a = sympy.Symbol('a')
# (1)
expr1 = -4 * x + 3 * y + a
expr2 = 3 * x + 4 * y - 7 * a
d = sympy.solve([expr1, expr2], [x,y])
# print(d) # 直線L、Mの交点が (a, a) とわかる
# 円Cに(a, a)を代入
sympy.var('x, y, a')
x = d[x] # xに上で得た交点のx座標代入
y = d[y] # yに上で得た交点のy座標代入
sol = sympy.solve (1 * x**2 - 2 * a * x + y**2 - 4 * y + 4, a)
sympy.init_printing()
print(sol) # 解答のリスト(今回は 1 のみ)取得
# (2)
# 不等号の解はIntervalで区間の型にして、和集合を取ればよいが、今回は等式から境界値を求めて終わる
dis = abs(6 - 3 * a)/5
# dis^2 = abs(a)を両辺二乗して解く
expr3 = 16 * a**2 + 36 * a - 36
d2 = sympy.solve([expr3])
print(d2) # [{a: -3}, {a: 3/4}] 共有店の個数が変化する境界値
# (3)
# 省略
第三問
(1) 問題文を見て、パッと思い浮かぶ解法として、以下の三つがあると思います。
・数学的帰納法
・式変形による不等式の導出
・関数化:$f(n)=3^n-(2^n+n^2+8)$ として、$n≧3$ で $f(n)>0$ であることを示す
解答では数学的帰納法を用いていますが、プログラミングで解くという観点から言うと、関数化が一番簡単だと思います。
(2) (1)で $n≧3$ で $f(n)>0$ であることを示しているので、$f(n)≦0$ となるためには、少なくとも $n<3$ である必要があります。また今回 $n$ は正の整数という条件があるため、$n=1,2$ が解の候補であることがわかります。ここまでわかれば、あとは実際に代入して題意が成立するか確かめるだけですね。
(3) $a,b,n$全て0以上であるため、等式 $2^n+n^2+8=3^n+an+b$ が成立するのは、$n=1$ or $2$ のみ。
それではコーディングしていきます。
# (1)
import math
# f(n)
def func(n):
return 3**n - (2**n + n**2 + 8)
# f'(n)
def func_p1(n):
return 3**n * math.log(3) - (2**n * math.log(2) + 2 * n)
# f''(n)
def func_p2(n):
return 3**n * math.log(3)**2 - 2**n * math.log(2)**2
# print(func_p2(3)) # 28.74 ← 0以上
# かつ n > 3 で func_p2(n) >0 (∵ 3**n >> 2**n)
# よって n > 3 で func_p1(n) は単調増加 ...(1)
# また print(func_p1(3)) # 18.11 ← 0以上 ...(2)
# (1),(2)より n > 3 で func(n)も単調増加 ...(3)
# さらに print(func(3)) # 2 ← 0以上 ...(4)
# したがって、(3),(4)より n >= 3 で func(n) > 0
# Q.E.D
# (2)
print(func(1), func(2)) # -8 -7 よって f(n) < 0 、ゆえに題意を満たす n は 1,2
# (3)
lis = [] # 解リスト
for a in range(9): # n,a,b >= 0 より、a,b は 0~8 で回せば十分
for b in range(9):
# n=1の時
jouken1 = a + b # joken1 = 8
# n=2の時
jouken2 = 2 * a + b # joken2 = 7
if jouken1 == 8:
lis.append((a,b,1))
elif jouken2 == 7:
lis.append((a,b,2))
else:
continue
print(lis)
#[(0, 7, 2), (0, 8, 1), (1, 5, 2), (1, 7, 1), (2, 3, 2), (2, 6, 1), (3, 1, 2), (3, 5, 1), (4, 4, 1), (5, 3, 1), (6, 2, 1), (7, 1, 1), (8, 0, 1)]
今回はここで終了したいと思います。
残りの問題も暇すぎて死にそうになったらやるかもしれませんww
初めてPythonを用いて連立方程式を解いたのですが、素晴らしいですね。
本当に何でも出来ちゃいます、Python凄い!
またやってみたいもの、面白そうなものが浮かんだら、ゆるーくやっていこうと思います。
ご覧いただき、ありがとうございました。