문제 설명
https://www.acmicpc.net/problem/1876
지름이 20cm 인 볼링공을 너비 105cm 인 레인 위에서 굴린다.
볼링공이 구르기 시작한 첫 위치는 레인의 정 가운데 위치이고, 해당 위치에서 x도 각도로 굴린다.
굴러간 공은 레인 벽과 부딪히면 입사각과 동일한 각도로 반사되어 튕긴다.
볼링공이 구르기 시작한 첫 위치로부터 T 미터 떨어진 곳에 지름 12cm 인 볼링 핀이 있다.
처음 굴리기 시작한 각도 x 와 볼링공과 볼링핀 사이 거리 T 가 주어질 때, 이 볼링공이 볼링핀을 맞히는지 여부를 출력하라.
접근 방법
우선 각도에 따라서 공이 여러번 튕길 수 있고, 매번 튕기는 것을 다 시뮬레이션으로 구현하는 것은 너무 복잡해보였다.
그래서 수학적으로 문제를 풀 수 있을 것 같아서 태블릿에 그려가면서 문제를 추상화해보았다.
처음에는 단순히 직선을 그려서 튕기는 과정을 생각했는데, 움직이는 건 점이 아니라 공이므로 공이 움직이는 방법으로 추상화해야 한다.
공이 이동하는 것을 공의 중심이 이동하는 과정으로 추상화 해보면, 볼링공의 반지름이 10cm 이므로 85cm 폭의 레인에서 점이 왔다갔다 하는 것으로 추상화할 수 있다.
볼링핀도 똑같이 점으로 추상화하면, T미터 떨어진 곳에 점을 찍고 이 점과 볼링공의 이동경로 직선사이 거리를 재서 그 거리가 볼링핀의 반지름과 볼링공의 반지름 합인 16cm 미만이면 충돌한다고 볼 수 있다.
근데 입사각과 반사각을 고려하면 직선 식을 매번 바꿔서 계산해야 하기 때문에 불편하다.
볼링공이 튕기는 과정을 이렇게 확장해서 생각하면
입사각과 반사각이 같다는 점을 이용해 레인을 옆에 이어 붙여서 하나의 직선으로 계산하도록 변환할 수 있다.
이때 그림에서 보는 것처럼 볼링핀의 위치는 매번 85cm 씩 이동한 상태에 대해서 거리를 구하면 된다.
이제 구체적인 수식을 생각해보자.
먼저 좌표평면으로 이 문제를 생각하기 위해서 먼저 화면을 조금 돌려주었다.
볼링공의 시작 좌표를 (0, 85/2) 로, 볼링 핀의 위치를 (100*T, 85/2 + 85n) 로 둔다. (T는 단위가 미터이므로 cm로 변환해야 하며, 85cm 마다 볼링핀을 배치해서 생각해야 하므로 그 값을 n으로 두었다.)
볼링공이 100T cm 위치에 도착했을 때의 y 좌표를 y1 이라고 하고,
그 점을 기준으로 인근의 가까운 볼링핀의 y 좌표를 y2 라고 하고,
해당 볼링핀에서 볼링공의 이동경로 직선에 내린 수선의 길이를 k 라고 하면 (우리가 구하려는 것은 k 가 16 미만인지 확인하는 것)
p = | y1 - y2 | 라고 할 때
cos x = k / p
k = p cos x
라는 식을 구할 수 있다.
그런데 여기에서 계산을 더 간편하게 하기 위해, 모든 점과 직선을 -85/2 만큼 평행이동해서 생각해보면
최종적으로 원점을 지나는 기울기가 tan x 인 직선에 대해, 직선에서 제일 가까운 (100T, 85n) 위치에 있는 점의 거리가 16미만인지 확인하는 것과 같다.
이때 n 의 값은 (tan x) * 100T 값을 85로 나눈 몫과 그 앞 뒤 1칸을 생각하면 된다.
정답 코드
import sys
from math import tan, radians, cos
input = sys.stdin.readline
n = int(input())
for _ in range(n):
t, x = map(float, input().split())
rad_x = radians(x)
a = tan(rad_x)
t = t*100
y = a * t
ans = "no"
for i in range(5):
check_pos = (y//85 + i) * 85
dist = abs(check_pos - y) * cos(rad_x)
if dist < 16:
ans = "yes"
break
print(ans)
tan 45 를 구하니까 계속 0.9999999 가 나와서 어떻게든 정밀도를 높여보려고 Decimal 을 썼는데, 그래도 1.0 은 결국 안나왔다.
어차피 구하는 것은 점과 직선 사이 거리가 16 미만인지만 구하면 되므로 이 정도 오차는 괜찮겠다고 생각해서 제출했고 AC를 받았다.
'알고리즘 (PS) > BOJ' 카테고리의 다른 글
[백준] 1248 - Guess (G3) (0) | 2025.03.20 |
---|---|
[백준] 1166 - 선물 (0) | 2024.11.13 |
[백준] 4315 - 나무 위의 구슬 (Python) (0) | 2024.11.12 |
[백준] 4436 - 엘프의 검 (0) | 2024.11.09 |
[백준] 11437 - LCA (Python) (0) | 2024.11.08 |