(BOJ20149 선분 교차 3
문제 설명
- 이 글은 텍스트와 코드 기반으로 작성되어, 이해가 어려울 수 있음.
- 문제는 매우 간단하다.
- 두 선분의 끝점이 주어지고, 교차하는지 판별하면 된다.
- 우선, 선분 교차를 잘 이해하고 해결하기 위해 CCW과 관련한 지식이 필요하다.
- 두 선분이 있을 때, 전혀 다른 위치이면 오히려 쉽게 판별할 수 있지만, 만약 두 선분이 일직선상에 있는 등의 경우를 판별할 때 편리하게 할 수 있다.
- 만약 선분위치를 분류하면 크게 3가지로 분류가 된다.
- 하나의 직선 위에 있는 경우
- 교차할 수 있는 위치
- 교차할 수 없는 위치
- 그리고 각 경우를 잘 구분하여 문제를 해결한다.
문제 풀이
x1, y1, x2, y2 = MIIS()
x3, y3, x4, y4 = MIIS()
ccw1 = ccw(x1, y1, x2, y2, x3, y3)
ccw2 = ccw(x1, y1, x2, y2, x4, y4)
ccw3 = ccw(x3, y3, x4, y4, x1, y1)
ccw4 = ccw(x3, y3, x4, y4, x2, y2)
tmp1, tmp2 = ccw1 * ccw2, ccw3 * ccw4
- 우선 총 주어진 4개의 점에 대한 ccw를 구하고,
- 각각 선분 기준으로 구한 ccw끼리 곱한다.
- 이렇게 하면, 하나의 선분 기준으로 다른 선분의 두 점의 위치를 파악할 수 있다.
if not tmp1 and not tmp2:
if (x1, y1) > (x2, y2):
x1, y1, x2, y2 = x2, y2, x1, y1
if (x3, y3) > (x4, y4):
x3, y3, x4, y4 = x4, y4, x3, y3
if (x1, y1) <= (x4, y4) and (x2, y2) >= (x3, y3):
print(1)
get_point((x1, y1), (x2, y2), (x3, y3), (x4, y4))
else:
print(0)
- 만약 tmp1, tmp2 값이 모두 0인경우는 두 선분이 하나의 직선 위에 있거나, 하나의 점을 공유하는 경우이다.
- 이 때, 두 선분의 위치를 판별하기 위해 왼쪽 아래의 점, 오른쪽 위의 점으로 구분하고,
- 선분이 교차하는 경우 1을 출력, 아니면 0을 출력한다.
- 선분이 교차하는 경우 교점이 유일한지 확인한다. 해당 함수는 뒤에서 다시 다루겠다.
if tmp1 <= 0 and tmp2 <= 0:
print(1)
get_point((x1, y1), (x2, y2), (x3, y3), (x4, y4))
else:
print(0)
- 위의 경우가 아니라면, 선분이 교차하거나 교차하지 않는 경우다.
- 만약 선분이 교차하려면 tmp1, tmp2의 값 모두 0이하가 되야 하고,
def get_point(A: tuple, B: tuple, C: tuple, D: tuple):
x1, y1 = A
x2, y2 = B
x3, y3 = C
x4, y4 = D
m = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if m:
x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / m
y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / m
print(x, y)
else:
if B == C and A <= C:
print(*B)
elif A == D and C <= A:
print(*A)
- 교점을 찾는 함수
- 도 선분을 직선으로 생각하여, 두 교점을 찾고 출력한다.
참조