수학은 비대면 강의입니다 - 19532
Category: Baekjoon
Tags: bruteforce algorithm
시행 착오 1 🥲
연립 일차 방정식의 경우, 두 직선의 교차점은 하나이기 때문에 x,y도 모두 하나씩 존재
a, b, c, d, e, f = map(int, input().split())
a1 = a * d
b1 = b * d
c1 = c * d
d1 = d * a
e1 = e * a
f1 = f * a
y = (c1 - f1) / (b1 - e1)
x = (c1 - b1 * y) / (a1)
print(int(x), int(y)) # x,y는 모두 정수임
위의 방법으로 풀었더니 -> 런타임 에러 발생(zero-division error)
(b1 - e1)이랑 a1이 0인 경우를 고려해주지 않아서 발생한 것 같다. 이 말은 a 혹은 d가 0일 경우가 존재하는데, 이때 나머지 값들도 모두 0을 곱해주게 되는 문제도 발생한다. 예외 처리를 시도해보려고 했지만, 애초에 초반에 a와 d를 곱할 때부터 경우를 나눠서 해줘야해서 매우 복잡했다.
시행 착오 2 🥲
결국 더 간단하게 해결할 방법을 찾아봤는데,
행렬의 곱셈으로 해결할 수 있었다..!
선대 공부를 좀 곁들여보면,
행렬은 연립 일차방정식의 해를 구하기 위해서 연구되었다.
행렬을 이용한 연립 일차방정식 풀이법 2가지는 :
- 가우스-조던-소거법 : 행렬을 간소화해서 연립방정식 재구성
-
역행렬을 이용하는 방식 : $Ax = B$에서 $A$의 역행렬이 존재하는 경우, 양변에 $A$의 역행렬을 곱해서 $x$의 해를 구할 수 있다. (존재하지 않는 경우: 해 존재 X)
a, b, c, d, e, f = map(int, input().split())
mat = [a, b, d, e]
det = a * e - b * d
mat_rev = [e / det, (-b) / det, (-d) / det, a / det]
x = (mat_rev[0] * c + mat_rev[1] * f)
y = (mat_rev[2] * c + mat_rev[3] * f)
print(x, y) # 1.9999999999999998 -1.0
위의 방법을 적용해서 풀어봤지만 소숫점에서 미세한 오차가 발생
이유를 찾아본 결과, 우리가 사용하는 십진법에서의 소수는 컴퓨터가 이해하는 이진 소수로 정확하게 변환될 수 없다고 한다.
결국 값을 근사하게 되면서 문제가 발생하는 것.
맞았습니다! 코드
나눗셈을 바로 하지 않고 계산 후 마지막에 하는 방식으로 수정했다.
# 맞은 풀이 - 행렬의 곱셈
a, b, c, d, e, f = map(int, input().split())
mat = [a, b, d, e]
mat_rev = [e, -b, -d, a]
det = a * e - b * d
x = (mat_rev[0] * c + mat_rev[1] * f) / det
y = (mat_rev[2] * c + mat_rev[3] * f) / det
print(int(x), int(y)) # 2 -1