문제 링크
- http://icpc.me/18664
사용 알고리즘
- DP
- Bitmask
시간복잡도
- $O(N^2 2^N + NS)$
풀이
$i$번 정점에 붙은 토큰의 개수를 $A_i$, 정점 $U_i, V_i$를 연결하는 간선의 용량을 $B_i = \min(A_{U_i}, A_{V_i})$라고 합시다. 이 문제는 아래 조건을 만족하는 $A_i$를 구하는 문제입니다.
- $\sum A_i \leq S$ : $\sum A_i < K$라면 아무 정점에 토큰을 더 붙여주면 됩니다.
- $\sum B_i$를 최대화
집합 $S_i = {v \vert A_v \geq i}$를 정의합시다. 토큰이 1개 이상 붙어있는 정점들을 덮는 덮개, 2개 이상 붙어있는 정점들을 덮는 덮개, …라고 생각하면 편합니다. $A_i$는 $i$번 정점을 포함하는 집합(덮개)의 개수가 됩니다.
또한, $B_i$는 ($U_i$를 포함하는 집합)과 (V_i를 포함하는 집합)의 교집합의 크기 = ($U_i, V_i$를 모두 포함하는 교집합의 크기)가 됩니다.
$f(S_i)$를 집합 $S_i$에 완전히 포함되는 간선의 개수로 정의하면, $\sum B_i = \sum f(S_i)$입니다. 이제 문제의 조건을 다시 정리합시다.
- $\sum \vert S_i \vert \leq S$
- $S_{i+1} \subset S_i$ : 토큰이 $i+1$개 이상 붙은 정점은 당연히 $i$개 이상 붙어있습니다.
- $\sum f(S_i)$를 최대화
2번 조건을 제외하고 1번과 3번 조건만 생각하면, 무게가 $\vert S_i \vert$이고 가치가 $f(S_i)$인 knapsack문제가 됩니다. $2^N$개의 부분집합을 모두 보는 것은 $O(2^NS)$로, 너무 느립니다.
잘 생각해보면, $1 \leq \vert S_i \vert \leq N$이기 때문에, 크기가 $i$이면서 $f(S_i)$가 최대가 되는 $S_i$를 미리 전처리한다면 $O(NS)$에 knapsack문제를 풀 수 있습니다. 크기가 $i$이면서 $f(S_i)$가 최대가 되는 $S_i$는 $O(2^N N^2)$에 구할 수 있습니다.
이렇게 구한 최적해는 2번 조건을 항상 만족합니다.
두 집합 $S_i, S_j$에 대해, $f(S_i) + f(S_j) \leq f(S_i \cup S_j) + f(S_i \cap S_j)$이기 때문에 두 집합이 서로 포함관계에 있는 것이 최적입니다. 그러므로 항상 2번 조건을 만족합니다.
전체 코드
1 |
|