문제 링크
- http://icpc.me/14832
문제 출처
- Google Code Jam 2017 World Finals A2
사용 알고리즘
- 이분 매칭
- 투포인터
시간복잡도
- $O(N^2)$ per testcase
풀이
$O(N^4), O(N^3), O(N^2)$ 풀이를 차례대로 알아봅시다. 실제 대회에서는 $O(N^3)$ 풀이를 구현하면 10점, $O(N^2)$ 풀이를 구현하면 25점을 받을 수 있었습니다.
$O(N^4)$
각 주사위는 최대 한 개의 수를 표현하게 됩니다. 주사위가 하나의 수를 선택한다는 점에서 이분 매칭을 생각해볼 수 있습니다.
주사위의 집합 $L$, 한 번 이상 등장하는 수의 집합 $R$, 주사위와 그 주사위에 써있는 수를 연결한 간선 집합 $E$가 있을 때, 적당한 집합 $r \subset R$에 대해 이분 그래프 $G_r = (L, r, E)$의 최대 매칭을 구하는 문제로 환원할 수 있습니다.
적당한 집합 $r \subset R$의 원소를 모두 정렬하면 연속한 자연수가 되어야 하고, 정렬된 배열의 구간을 선택한다고 생각하면 $O(N^2)$ 가지의 구간을 생각할 수 있습니다.
$O(\vert L \cup r \vert \cdot \vert E \vert) = O(N^2)$ 이분 매칭을 $O(N^2)$번 수행하면 $O(N^4)$에 문제를 풀 수 있습니다.
$O(N^3)$
투포인터를 이용하면 $O(N)$개의 구간만 봐도 충분합니다.
현재 구간을 나타내는 $r$이 있을 때, 세 가지 케이스로 분류할 수 있습니다.
- $e \in R, e = \max(r) + 1$인 원소 $e$가 존재하지 않음
- $e$를 $r$에 추가했을 때 매칭의 개수가 증가
- 증가하지 않음
2번의 경우 구간의 끝점을 뒤로 1만큼 밀고, 3번의 경우에는 구간의 시작점을 1만큼 뒤로 당기면 됩니다.
마지막으로 1번의 경우에는 끝점을 뒤로 1만큼 밀고, 시작점을 끝점과 동일하게 만들어주면 됩니다.
총 $O(N)$개의 구간에 대해 $O(N^2)$ 이분 매칭을 수행하면 $O(N^3)$에 문제를 풀 수 있고, Dice Straight (Small) 문제에서 AC를 받을 수 있습니다.
$O(N^2)$
이제 구간의 개수를 더 줄이는 것은 불가능합니다. 이분 매칭을 어떻게 최적화할 수 있을까요?
투포인터에서 포인터의 이동 과정을 생각해봅시다.
끝점이 이동하면 최대 1만큼 유량을 더 흘리게 됩니다. 반대로, 시작점이 이동하면 최대 1만큼 유량을 제거하게 됩니다. 두 연산은 각각 $O(N)$번 수행하게 됩니다.
1만큼 유량을 흘리는 것은, 간선을 추가하고 DFS를 이용해 Augmenting Path를 찾아주는 것으로 $O(N)$에 수행할 수 있습니다.
유량을 1만큼 제거하는 것은, 제거하고자 하는 정점 $v \in r$에 대해, $v$와 매칭을 이루고 있는 정점 $u \in L$을 찾아서 두 정점 사이의 유량을 제거하면 됩니다. 이 과정도 $O(N)$에 수행할 수 있습니다.
따라서, 투포인터에서 시작점과 끝점이 각각 $O(N)$번 이동하고, 포인터가 이동할 때마다 유량의 변화를 $O(N)$에 계산할 수 있으므로 $O(N^2)$에 문제를 풀 수 있습니다.
본 대회의 시간 제한은 120초였지만 BOJ는 30초로 세팅되어 있어 상수 커팅이 필요할 수 있습니다.
전체 코드
1 |
|