문제 링크
- http://icpc.me/17625
문제 출처
- 2019 KOI 고등부 4번
사용 알고리즘
- Rotating Sweep Line
시간복잡도
- $O(N^2 \log N)$
풀이
Subtask 1을 잘 생각해보면, 정답은 항상 아래 두 형태 중 하나라는 것을 알 수 있습니다.
- 두 점 $p_1, p_2$를 잇는 선분의 수직이등분선
- 세 점 $p_1, p_2, p_3$에 대해, $p_1$에서 선분 $p_2p_3$에 내린 수선의 수직이등분선
Subtask 3 ($N \leq 500$, 44점, $O(N^3)$)
이 문제를 $O(N^3)$에 해결하는 방법을 먼저 알아봅시다.
1번 케이스에 해당하는 직선 후보는 $O(N^2)$개 존재하고, 각 직선이 유효한지(두 점 $p_1, p_2$ 사이에 다른 점이 없는지) 확인하는데 $O(N)$이 걸리므로 총 $O(N^3)$에 처리할 수 있습니다.
2번 케이스는 약간 다른 방법으로 해결합니다.
$p_2, p_3$를 고정합시다. 이때 $p_1$이 될 수 있는 후보는 (1) 선분 $p_2p_3$의 왼쪽에 있는 점($ccw(p_2, p_3, p_1) = 1$) 중 선분과 가장 가까운 점, (2) 선분 $p_2p_3$의 오른쪽에 있는 점($ccw(p_2, p_3, p_1) = -1$) 중 선분과 가장 가까운 점, 두 가지로 축약할 수 있습니다.
그러므로 $p_2, p_3$를 고정하는 $O(N^2)$가지에 대해, 양쪽에서 가장 가까운 점을 $O(N)$만에 찾아주면 총 $O(N^3)$에 처리할 수 있습니다.
Subtask 5($N \leq 2000$, 100점, $O(N^2 \log N)$)
(1) 임의의 두 점 $p_1, p_2$ 사이에 다른 점이 없는지 판별하는 것, (2) 어떤 선분 $p_2p_3$과 가장 가까운 점을 찾는 것에 $O(N)$이라는 시간이 걸립니다. 이 시간을 줄일 수는 없을까요?
Rotating Sweep Line이라는 테크닉이 이 질문을 해결해줄 수 있습니다.
2번을 처리하는 방법을 먼저 알아봅시다.
선분 $p_2p_3$을 고정하고, 해당 선분과 수직인 직선에 모든 점을 사영시켜봅시다. 사영된 지점을 기준으로 번호를 붙여주면, 선분을 구성하는 두 점을 $i, j$번 점이라고 했을 때 왼쪽에서 가장 가까운 점은 $i-1$번 점이 되고, 오른쪽에서 가장 가까운 점은 $j+1$번 점이 됩니다.
비슷한 방식으로 1번도 처리할 수 있습니다.
선분 $p_1p_2$와 평행한 선분에 모든 점을 사영한 뒤, $p_1$과 $p_2$의 번호가 인접한지 확인하면 됩니다.
각 직선마다 점의 번호가 어떻게 바뀌는지 빠르게 구할 수 있다면 이 문제를 해결할 수 있습니다.
먼저, 주어지는 직선은 최대 $O(N^2)$가지입니다. 직선을 기울기 순서대로 보면, 각 직선마다 번호가 바뀌는 점은 최대 한 쌍만 존재하고, 그 두 점은 번호가 바뀌기 직전/직후에 인접한 상태를 유지합니다.
그러므로 직선을 기울기 순으로 $O(N^2 \log N)$에 정렬한 후, $O(N^2)$개의 직선은 순회하는 것으로 문제를 해결할 수 있습니다.
전체 코드
1 |
|