ABC183 B問題 Billiards 数学的問題を解く

ABC183 B問題 Billiards という数学的問題を解説します。

2次元平面でビリヤードをしていて、玉が (S_x, S_y)にある時、x軸の壁に一回反射させてから (G_x, G_y)に当てるには、x軸の壁のどの位置に当てたら良いか、x座標を求める問題です。
反射するときに入射角と反射角は等しくなります。

atcoder.jp

中学校の数学でなんとかなるレベルでした。入射角とか反射角とか懐かしい言葉。
入射角と反射角が等しいので、 (G_x, G_y)からx軸に線対称の点 (G_x, -G_y)と最初の位置 (S_x, S_y)を直線で結んで、x軸と交わるところのx座標が答えになります。

その直線の方程式をいったん、 y = ax + bと置きます。
傾き aは、 a = \frac {S_y + G_y} {S_x - G_x}です。
 y = \frac {S_y + G_y} {S_x - G_x} x + bとなります。
次にbを求めるには、xとyに (S_x, S_y)を代入します。
 S_y = \frac {S_y + G_y} {S_x - G_x} S_x + b \\ \Leftrightarrow b = S_y - \frac {S_y + G_y} {S_x - G_x} S_x
なので、 (S_x, S_y)とx軸に線対称の点 (G_x, -G_y)を結ぶ直線の方程式は、
 y = \frac {S_y + G_y} {S_x - G_x} x + S_y - \frac {S_y + G_y} {S_x - G_x} S_xになります。
あとは y = 0として xを求めます。
 0 = \frac {S_y + G_y} {S_x - G_x} x + S_y - \frac {S_y + G_y} {S_x - G_x} S_x \\ \Leftrightarrow -S_y + \frac {S_y + G_y} {S_x - G_x} S_x = \frac {S_y + G_y} {S_x - G_x} x \\ \Leftrightarrow -S_y \frac {S_x - G_x} {S_y + G_y} + S_x = x \\ \Leftrightarrow x = \frac {-S_y(S_x - G_x) + S_x(S_y + G_y)} {S_y + G_y}
ポイントとしては、誤差が減るように割り算の回数を減らすところと、最後にround関数で丸めてあげます。

コードは以下のようになります。

Sx, Sy, Gx, Gy = map(int, input().split())
ans = round(((-Sy * (Sx - Gx)) + (Sx * (Sy + Gy))) / (Sy + Gy), 10)
print(ans)