이 글은 2026년 봄학기에 KAIST에서 수강한 Algorithms for NP-hard Problems 강의의 lecture note를 기반으로 한다.

이 글은 PS에서 다루는 그래프 이론에 익숙한 사람을 예상 독자로 하여, 쉬운 전달을 목표로 한다. 엄밀한 정의와 서술은 lecture note 원본에서 확인할 수 있다. 그래프에 관련된 일반적인 notation은 따로 정의하지 않는다. 정점 nn개, 간선 mm개를 가진 그래프를 다룰 때 O(f(k,n,m))O^*(f(k, n, m))O(f(k,n,m)poly(k+n+m))O(f(k, n, m) \cdot \text{poly}(k+n+m)) 정도의 뜻을 가진다. 즉, polynomial factor는 무시한다.

O(4klp(G))O^*(4^{k-\text{lp}^*(G)})-time algorithm for VERTEX COVER

VERTEX COVER

입력: Graph GG와 양의 정수 kk가 주어진다.

출력: GG의 크기 kk 이하인 vertex cover가 존재하는가?

그래프 GG에 대해 XV(G)X \subseteq V(G)GG의 vertex cover라는 것은 GG의 모든 간선에 대해 최소 한 개의 endpoint가 XX에 포함된다는 것을 의미한다.

1편에서는 vertex cover 문제를 간단한 branching으로 접근했었다. 이번에는 linear programming이라는 도구를 사용한 방법을 알아보자.

Linear programming은 주어진 문제를 선형 연립부등식과 선형 목표 함수로 모델링하여 푸는 기법이다. 최적화 문제를 풀기 위해 아주 많이 연구되어 왔으며, 따라서 이를 푸는 빠른 알고리즘이 많이 알려져 있고 다항 시간에 해를 찾을 수 있음 역시 알려져 있다.

VERTEX COVER 문제를 LP로 모델링해보자. 집합 XX를 잡는다는 것은 각 정점을 변수로 두고, 00 또는 11을 부여하는 것으로 생각할 수 있다. XX가 vertex cover라는 것은 모든 간선에 대해 양쪽 endpoint에 대응되는 변수(앞으로는 이 값을 정점의 가중치라고 부르겠다)의 합이 11 이상이라는 것을 의미한다. 따라서 vertex cover 조건은 간선의 개수와 같은 개수의 선형 부등식으로 표현 가능하다. 그러나 각 변수에 00 또는 11을 넣는다는 조건은 표현할 수 없다. 따라서 조건을 조금 약화시켜 각 변수가 00 이상이라고만 하자. 이때 목표 함수는 모든 변수의 합이 되고, 최솟값을 구하는 문제로 볼 수 있다.

이렇게 만든 약화된 LP의 해를 xx^*라고 하고, 정점 vV(G)v \in V(G)에 대해 xx^*에서 vv에 부여된 값은 xvx^*_v로 표기하자. 또한 vV(G)xv\sum \limits_{v \in V(G)} x^*_vlp(G)\text{lp}^*(G)라고 하자. 조건을 추가할 때 최적해의 크기가 감소할 수 없으므로 실제 vertex cover XX에 대해 Xlp(G)|X| \geq \text{lp}^*(G)임은 자명하다. 따라서 k<lp(G)k<\text{lp}^*(G)면 바로 False를 return할 수 있다.

이제 main part로 들어가자. V(G)V(G)를 세 집합으로 분리하고 시작할 것이다. xvx^*_v0.50.5보다 작은 vv의 집합을 CC, 0.50.5보다 큰 vv의 집합을 HH, 정확히 0.50.5vv의 집합을 RR이라 하자. 이때 CC 내부에는 간선이 있을 수 없음을 쉽게 알 수 있다. 물론 CCRR 사이에도 간선이 있을 수 없다.

만약 HH의 어떤 부분집합 HH'에 대해 H>N(H)C|H'| > |N(H') \cap C|라고 해보자. 그렇다면 HH'에 속하는 정점의 가중치에서 ϵ\epsilon씩 빼고 N(H)CN(H') \cap C에 속하는 정점의 가중치에서 ϵ\epsilon씩 더하면 조건에 모순을 만들지 않으면서 전체 가중치 합을 감소시킬 수 있다. 따라서 모든 HHH' \subseteq H에 대해 HN(H)C|H'| \leq |N(H') \cap C|이다.

이제 HH에서 가중치가 11이 아닌 정점의 집합 XXCC에서 가중치가 00이 아닌 집합 YY를 생각해보자. 물론 XXCYC \setminus Y 사이에는 간선이 존재할 수 없다. 따라서 YN(X)C|Y| \geq |N(X) \cap C|이다. 이제 δ=min({1xv:vX}{xv:vY})\delta = \min(\{1-x^*_v: v \in X\} \cup \{x^*_v: v \in Y\})라고 정의했을 때, XX에 속한 각 정점의 가중치에서 δ\delta를 더하고 YY에 속한 각 정점의 가중치에서 δ\delta를 빼도 LP의 조건에 문제가 없음을 알 수 있다. 이를 반복하면 결국 C,R,HC, R, H를 각각 가중치가 00, 0.50.5, 11인 점의 집합으로 만들면서 총 가중치 합을 증가시키지 않을 수 있다.

물론 위 과정을 그대로 실행할 필요는 없고, LP를 풀고 얻은 C,R,HC, R, H에 처음부터 00, 0.50.5, 11을 가중치로 줘도 optimal solution을 얻음이 증명되었다고 보면 된다. 즉, xx^*를 half-integral solution으로 생각할 수 있다.

이제 GG의 optimal한 vertex cover XX를 하나 생각해보자. 만약 HH에서 XX에 속하지 않은 정점이 존재한다면, 그러한 점을 모은 HH'을 생각할 수 있다. 이때 vertex cover 조건에 의해 N(H)N(H')은 모두 XX에 속한다. 위에서 HN(H)C|H'| \leq |N(H') \cap C|를 보였으므로 XX에서 N(H)CN(H') \cap C를 빼고 HH'을 넣어도 된다는 결론을 얻을 수 있다. 즉, HH를 포함하는 optimal한 vertex cover XX가 존재한다. 이때 XC=X \cap C = \emptyset임도 쉽게 관찰 가능하다.

이제 GG에 크기 kk짜리 vertex cover가 있다는 것은 G[R]G[R]에 크기 kHk-|H|짜리 vertex cover가 있다는 사실과 동치임을 알 수 있다.

1편의 기본적인 branching algorithm을 떠올리자. 단순히 간선을 하나 잡고 양쪽 endpoint 중 하나를 vertex cover에 넣은 branch (Gv,k1)(G-v, k-1)에 들어가기를 반복하는 알고리즘이다.

이때 위 일련의 과정을 통해 (G,k)(G, k)(G[R],kH)(G[R], k-|H|)로 바꾸고 branch에 들어가기를 매 branch 전에 반복한다면 depth를 줄일 수 있다. 정확히는, 어떤 정점 vv에 대해 lp(G)=lp(Gv)+1\text{lp}^*(G) = \text{lp}^*(G-v)+1이라면 GvG-v에서 LP를 풀고 얻은 C,R,HC, R, H에 대해 C,R,H{v}C, R, H \cup \{v\}GG의 optimal solution을 만들어주는 분할이 되므로, (G,k)(G, k) 대신 (G[R],kH{v})(G[R], k-|H \cup \{v\}|)에 대한 문제로 축소하는 과정을 최대한 반복한 후에 branch로 들어간다고 하자. GG에서 아무 C,R,HC, R, H나 뽑지 않는 이유는 reduction을 끝까지 적용하고 나면 branch로 들어갈 때 lp\text{lp}^*의 값이 최대 0.50.5 감소한다는 보장을 얻기 위해서이다. 이렇게 설계한 알고리즘에서, kk는 branch로 내려갈 때 11 감소하고 lp\text{lp}^*는 최대 0.50.5 감소하므로 klp(G)k-\text{lp}^*(G)는 최소 0.50.5 감소한다. 따라서 depth는 최대 2(klp(G))2(k-\text{lp}^*(G))가 된다.

이로써 O(22(klp(G)))=O(4klp(G))O^*(2^{2(k-\text{lp}^*(G))}) = O^*(4^{k-\text{lp}^*(G)})-time에 동작하는 VERTEX COVER 문제의 알고리즘을 얻었다. 그러나 식의 형태를 보면 복잡한 과정을 거쳤음에도 아주 간단한 O(2k)O^*(2^k) 알고리즘보다 느릴 수도 있을 것 같아 보인다. 그러나, 만약 kk2lp(G)2\text{lp}^*(G) 이상이라면 RHR \cup H라는 kk 이하의 크기를 갖는 vertex cover를 얻을 수 있으므로 바로 True를 return할 수 있다. 이를 적용하면 우리의 알고리즘은 최대 O(2k)O^*(2^k) 시간에 동작하게 되며, 약화된 LP가 좋은 답을 내놓았을수록 빠른 시간에 동작하는 알고리즘임을 알 수 있다.