BOJ 1150 - 백업

image.png

거의 하루동안 끈기있게 고민한 문제이다. $4$번 째 풀이를 고안하다 맞았는데, 풀이과정을 접어서 보관해두긴 하겠다.

문제 지문은 단순하다.

일단 케이블을 이은 두 쌍 $(a,c)$와 $(b,d)$의 거리를 봤을 때 $a < b < c < d$라면 $(a,b) (c,d)$로 바꿔주는게 항상 최적이므로 $k$개의 케이블은 모두 인접한 도시에만 사용해줘야한다.

Trial 1 - DP

뭔가 DP같으니 먼저 DP로 시도해보도록 하겠다.

$dp[p][i]=i$번째 회사까지 봤을 때, $i$번째 회사는 항상 쌍에 오른쪽으로 포함되고 $p$개의 쌍을 지어줬을 때의 최소값이라고 하자.

점화식을 세워보자.

$x(i)$를 $i$의 위치라고 하자.

$$ dp[p][i]=\begin{cases} \infty&\text{if}~~p>\left\lfloor i/2 \right\rfloor~~\text{or}~~ p=0 ~~\text{or}~~ i \le 0\\ Min_{j=0}^{i-2} ~~ dp[p-1][j]+x(i)-x(i-1) &\text{otherwise} \end{cases} $$

$0-$based 인덱스이다.

$O(n^2)$ 짜리 점화식이 나왔는데, 이 문제가 그리디문제가 아니라면 DP최적화 기법을 사용해야 되는 문제같다.

뭔가 분할정복최적화 같아서 이전에 공부했던 내용을 살펴보았다.

아닌가?

DnC opt의 조건을 보니 최적해에 단조성만 있으면 된다.

위 점화식에서 $opt[p][i]$를 $dp[p-1][j]$가 최소가 될 때의 $j$라고 하자.

$opt[p][i] \le opt[p][i+1]$ 인가? $\Rightarrow$ 그렇다.

왜냐면 $i+1$와 $i$를 항상 이어주어야 해서 실제 DP값은 단조성이 없지만, 최적해로 고를 수 있는 $j$의 범위는 더 오른쪽으로 선택권이 넓어졌기 때문에 이전에 골랐던 $j$를 항상 골라줄 수 있기 때문이다.

따라서 구현 어떻게 하는지 기억도 잘 안나는(빨리 이 블로그에도 정리해야겠다) DnC를 구현법을 참고해서 구현하면 될 것 같다.

아 쉬바 구현하다 뭔가 이상해서 살펴보니 DnC opt의 시간복잡도는 $O(KNlg N)$이였다.

Trial 2 - Greedy

우리가 이어주어야 할 쌍은 $K$쌍이다.

그런데 하나의 쌍을 이을 때, 우린 총 $N-1$개의 구간 중, $2$혹은 $3$개의 구간을 못쓰게된다.

정확히 말하면 모든 구간의 길이의 합은 $x(N-1)-x(0)$인데, $i$와 $i+1$를 이었다고 하면,

$x(i+1)-x(i)$는 구간의 길이(정답)에 더해지고,

$x(i)-x(i-1)$과 $x(i+2)-x(i+1)$은 전체 구간의 길이에서 빼진다고 생각할 수 있다.

그럼 이걸 최대한 많이 빼면 정답아닐까?

근데 항상 원하는 구간만 모두 사용할 수 있을까?

$1 \le k \le \left\lfloor n/2 \right\rfloor$ 이다.

다음과 같이 가장 worst case로 이엇다고 해보자.

X는 이어지지 않은 도시이고 O는 이어진 도시이다.

X O - O X O - O X O - O X ...

각 $N$에 대해 $K$가 얼마나 적어야 저렇게 이을 수 있는지 보자.

N K
3 1
4 1

벌써 망했다. $N=4$라면 $K=2$ 까지 입력에서 들어올 수 있는데, 저딴식으로 이어버리면 안되기 때문이다.

연속된 $N$개의 도시는 최대 $\left\lfloor N/2 \right\rfloor$개의 $K$를 소모할 수 있다.

여기까지 생각하고 태그를 깠다.

여기까지의 추론이 틀린것은 아니였고 예상대로 Greedy + Priority Queue 였다.

이제 밥을 먹고 다시 생각해보겠다.


전체 구간에서 양옆 두 구간의 합이 더 긴것부터 제거해나갈 수 있는걸 이어나가는게 최적이라는 가설을 세웠다.

어떤걸 제거해갈 때 항상 남은 도시들로 소모할 수 있는 $K$가 몇개인지 관리할 수 있을까?

O --5-- O --5-- O --5-- O

처럼 되어있을 때, $N=4,K=2$인데 어떻게 중간걸 안고르고 왼쪽이나 오른쪽을 골라야한다 라고 판단을 할 수 있을까?

이것도 아닌듯

Trial 3

어떤걸 먼저 정렬해서 볼 생각을 하지 말고, 왼쪽부터 $K$개의 쌍을 먼저 짝지어준 다음, $i=2K$ 부터 시작해서 이전에 했던 선택과 교체해주도록 시도해보자.

이런식의 진행은 Greedy + PQ에서 흔한 패턴인데, 이런 문제를 너무 접한지 오래되어서 까먹었었다.

$N=5, K=2$ 라고 하자.

X - X X - X O

이고 다섯 번째껄 보고있는데,

X - X O  X - X

처럼 하나만 스왑해준다고 하자. 그런데 $\overline{01}$말고 $\overline{12}$을 선택할 수 있게 되었고 이게 최적일 수도 있는데, 한 번의 인덱스당 하나의 교체만 진행한다면 뭔가 완전하지 않다.

무언가 연쇄적으로 연산을 적용시켜줘야 할 것 같다.

O -100- O -1- O -100- O -150- O

우선 작은걸 최대한 모두 이어준 다음, 남은 쌍 개수를 $T$라고 하자.

$N=13, K=6$ 라 하자. 최대로 $T$가 많이 남았을 때, 다음처럼 $T=2$ 이다.

O [O O] O [O O] O [O O] O [O O] O

이제 무조건 연결되어있는 것 중 하나를 끊어야한다.

첫 번째껄 끊는다고 해보자. 양 옆 두개중에 하나에 붙여줄 수 있다.

(1) [O O] O O [O O] O [O O] O [O O] O
(2) O O [O O] [O O] O [O O] O [O O] O

즉, $[i, i+1]$를 끊는다고 할 때, 이것으로 인해 보는 손실(정답에 늘어나는 값)은 $-(x_{i+1}-x_i)+Min(x_i-x_{i-1}, x_{i+2}-x_{i+1})$ 이다.

이걸 우선순위큐로 관리하며 제일 손실이 없는것부터 끊어준다고 해보자.

저렇게 초기 상태에선 어떤걸 끊어서 좌우로 한 칸 밖에 못움직였지만, 하나를 끊어주고나니 그냥 바로 이어줄 수 있는 것도 생기고 그렇다.

그런데 어떤 $N$에 대해 최대로 생길 수 있는 $T$는 얼마일까? $T \le K$ 일텐데 말이다.

한번 표로 생각해보자.

$N$ Max $K$ $T$
3 1 0
4 2 1
5 2  

아닌듯 작은걸 최대로 이어준다는 것부터가 불가능


Trial 4 (AC)

사용하지 않은 도시는 0, 사용한 도시는 1로 생각한다.

처음에 모든 도시가 사용을 안하므로

0 0 0 0 0 0 0 0 0 ..

이다.

무조건 한 쌍을 이어주며 얻을 수 있는 가장 작은 길이를 우선순위큐로 관리해보자.

처음엔 $N-1$개의 구간에 대해 모두 우선순위 큐에 넣어둔다.

가장 비용이 적은 도시를 고른다.

0 0 0 0 1 - 1 0 0 0 ..

항상 어떤 0 사이엔 짝수개($0$포함)의 $1$이 있어야 한다.

그런데, $1~1$ 양 옆의 $0~0$을 보자.

이 두개를 이어주기 위해선 그 사이의 연결된 도시들의 연결 방향을 모두 뒤집은다음

0 0 0 1 - 1 1 - 1 0 0 ..

처럼 이어줄 수 있다.

그리고 정확히 우린 한 개의 연결을 추가했다.

이렇게 특정 구간을 반전시켰을 때 증가하게 되는 값은 구간합배열을 전처리해두면 $O(1)$에 구해줄 수 있다.

이제 우선순위큐를 쭉 돌리면서 특정 구간을 반전시켜서 얻는 값을 우선순위큐에 넣어버린다.

pop 했는데 벌써 사용하지 못하게 된 0 두개라면 skip한다.

그런데 항상 두 $0$ 바로 왼쪽 오른쪽이 그 다음 $0$인 구간이라는 보장은 없으므로 이건 적절한 자료구조 아무거나 사용해서 그 다음 $0$ 두 개를 $O(\log N)$ 정도에 찾아주자.

본인은 세그먼트 트리와 이분탐색으로 구현했지만 시간복잡도는 문제없다.

이런식으로 쭉 돌리면 정답이다.

이것이 최적인 이유는 Flow와 연관지어 augmenting path를 찾는 방법으로 생각하면 증명이 된다고 한다.

Tags:

Categories:

Updated:

Comments