본문으로 건너뛰기
김신건의 로그

Minimum Vertex Cover: 최소 정점 덮개

· 수정 · 📖 약 4분 · 1,326자/단어 #algorithm #graph #cover #np-hard #bipartite #matching
Minimum Vertex Cover, 정점 덮개, vertex cover, 최소 정점 커버, MVC, König's theorem, 쾨니히 정리

정의

Vertex Cover 는 그래프의 모든 간선이 최소 한 끝점을 포함하도록 하는 정점 집합입니다.

S 가 vertex cover <=> 모든 간선 (u, v) 에 대해 u in S 또는 v in S

Minimum Vertex Cover (MVC) 는 크기가 최소인 vertex cover 를 찾는 문제입니다.

  • 일반 그래프: NP-hard (다항 시간 알고리즘 없음)
  • 이분 그래프: König’s Theorem 으로 최대 매칭 = 최소 정점 덮개, 이분 매칭 으로 다항 시간 해결

문제 상황과 동기

감시 카메라 배치 문제: 모든 통로 (간선) 를 감시하려면 최소 몇 개의 교차로 (정점) 에 카메라를 설치해야 하는가?

그래프 종류복잡도방법
일반 그래프NP-hard2-근사 알고리즘
이분 그래프PKönig’s Theorem + 이분 매칭
트리O(N)DP
평면 그래프NP-hard특수 알고리즘 존재

최대 독립 집합 과의 관계: V \ MVC = 최대 독립 집합. 즉 MVC 를 구하면 최대 독립 집합도 구할 수 있습니다.

시각화

이분 그래프 예시 (Left: {1, 2, 3}, Right: {a, b}):

flowchart LR
    subgraph Left
        L1["1"]
        L2["2"]
        L3["3"]
    end
    subgraph Right
        Ra["a"]
        Rb["b"]
    end
    L1 --- Ra
    L2 --- Ra
    L2 --- Rb
    L3 --- Rb

최대 매칭 M = {(1, a), (3, b)}, 크기 2.

König’s Theorem 으로 MVC 구성:

  • 비매칭 왼쪽 정점: 2
  • 2 에서 교대 경로 BFS: 2 -> a (비매칭 간선) -> 1 (매칭 간선) -> (끝)
  • 2 에서 교대 경로 BFS: 2 -> b (비매칭 간선) -> 3 (매칭 간선) -> (끝)
  • 방문된 Left = {2, 1, 3}, 방문된 Right = {a, b}
  • MVC = (Left \ 방문된 Left) ∪ 방문된 Right = {} ∪ {a, b} = {a, b}

검증: (1,a) - a 포함, (2,a) - a 포함, (2,b) - b 포함, (3,b) - b 포함. 모든 간선 커버.

flowchart LR
    subgraph "MVC = {a, b}"
        L1b["1 (not in MVC)"]
        L2b["2 (not in MVC)"]
        L3b["3 (not in MVC)"]
        Rab["a (in MVC)"]
        Rbb["b (in MVC)"]
    end
    L1b --- Rab
    L2b --- Rab
    L2b --- Rbb
    L3b --- Rbb

König’s Theorem (이분 그래프)

|최소 vertex cover| = |최대 매칭| (이분 그래프에서)

증명 개요

|MVC| >= |최대 매칭|: 매칭의 각 간선은 서로 다른 정점을 공유하지 않으므로, vertex cover 는 각 매칭 간선에서 최소 1개 정점을 포함해야 합니다. 따라서 |MVC| >= |M|.

|MVC| <= |최대 매칭|: 아래 구성으로 |M| 크기의 vertex cover 를 만들 수 있습니다.

MVC 구성 알고리즘

최대 매칭 M 을 구한 뒤:

1. U = 왼쪽에서 M 에 포함되지 않은 정점 집합
2. Z = U 에서 시작하는 교대 경로 (alternating path) 로 도달 가능한 정점 집합
   - 교대 경로: 비매칭 간선 -> 매칭 간선 -> 비매칭 간선 -> ...
3. MVC = (Left \ Z_L) ∪ Z_R
   - Z_L = Z 에 속하는 왼쪽 정점
   - Z_R = Z 에 속하는 오른쪽 정점

알고리즘

이분 그래프에서 MVC

minimum_vertex_cover(G):
    // 1. 최대 매칭 M 구하기 (Hopcroft-Karp 또는 Kuhn)
    M = max_bipartite_matching(G)
    
    // 2. 비매칭 왼쪽 정점에서 교대 경로 BFS
    unmatched_left = { v in Left : v not in M }
    visited_left, visited_right = BFS_alternating(G, M, unmatched_left)
    
    // 3. MVC 구성
    MVC = (Left \ visited_left) ∪ visited_right
    return MVC

교대 경로 BFS

BFS_alternating(G, M, start):
    queue = start
    visited_L = set(start)
    visited_R = {}
    while queue not empty:
        u = queue.pop()  // 왼쪽 정점
        for v in neighbors(u):  // 비매칭 간선으로 오른쪽 이동
            if v not in visited_R:
                visited_R.add(v)
                if M[v] exists:  // 매칭 간선으로 왼쪽 이동
                    w = M[v]
                    if w not in visited_L:
                        visited_L.add(w)
                        queue.push(w)
    return visited_L, visited_R

일반 그래프 2-근사

2_approx_vertex_cover(G):
    cover = {}
    for each edge (u, v) not yet covered:
        cover.add(u)
        cover.add(v)
        // u, v 에 인접한 모든 간선 제거
    return cover

최대 매칭의 양 끝점을 모두 취하는 방법. |MVC| <= 2 * |OPT|.

구현

// 이분 그래프 최소 정점 덮개 (König's Theorem)
// 입력: 왼쪽 n개, 오른쪽 m개, 간선 목록
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 505;
vector<int> adj[MAXN];  // 왼쪽 -> 오른쪽 인접 리스트
int matchL[MAXN], matchR[MAXN];  // 매칭 결과
bool visited[MAXN];
int n, m;

bool dfs(int u) {
  for (int v : adj[u]) {
      if (!visited[v]) {
          visited[v] = true;
          if (matchR[v] == -1 || dfs(matchR[v])) {
              matchL[u] = v; matchR[v] = u;
              return true;
          }
      }
  }
  return false;
}

int max_matching() {
  fill(matchL, matchL + n + 1, -1);
  fill(matchR, matchR + m + 1, -1);
  int result = 0;
  for (int u = 1; u <= n; u++) {
      fill(visited, visited + m + 1, false);
      if (dfs(u)) result++;
  }
  return result;
}

// König's: 교대 경로 BFS
// visitedL[u] = true: 왼쪽 u 가 Z 에 속함
// visitedR[v] = true: 오른쪽 v 가 Z 에 속함
bool visitedL[MAXN], visitedR[MAXN];

void alternating_bfs() {
  queue<int> q;
  // 비매칭 왼쪽 정점에서 시작
  for (int u = 1; u <= n; u++) {
      if (matchL[u] == -1) {
          visitedL[u] = true;
          q.push(u);
      }
  }
  while (!q.empty()) {
      int u = q.front(); q.pop();
      for (int v : adj[u]) {
          if (!visitedR[v]) {
              visitedR[v] = true;
              int w = matchR[v];
              if (w != -1 && !visitedL[w]) {
                  visitedL[w] = true;
                  q.push(w);
              }
          }
      }
  }
}

int main() {
  ios::sync_with_stdio(0); cin.tie(0);
  int e; cin >> n >> m >> e;
  while (e--) {
      int u, v; cin >> u >> v;
      adj[u].push_back(v);
  }
  int matching = max_matching();
  alternating_bfs();

  // MVC = (Left \ visitedL) ∪ visitedR
  vector<pair<char,int>> mvc;
  for (int u = 1; u <= n; u++)
      if (!visitedL[u]) mvc.push_back({'L', u});
  for (int v = 1; v <= m; v++)
      if (visitedR[v]) mvc.push_back({'R', v});

  cout << "Matching size: " << matching << "\n";
  cout << "MVC size: " << mvc.size() << "\n";
  for (auto [side, idx] : mvc)
      cout << side << idx << " ";
  cout << "\n";
}
stdin
3 2 4
1 1
2 1
2 2
3 2
결과
Matching size: 2
MVC size: 2
Ra Rb

복잡도

항목
최대 매칭 (Kuhn)O(VE)
최대 매칭 (Hopcroft-Karp)O(E * sqrt(V))
König’s MVC 구성O(V + E) (BFS)
2-근사 (일반 그래프)O(V + E)

관련 정리

최대 독립 집합 (Maximum Independent Set)

|MIS| = |V| - |MVC|

이분 그래프에서 MVC 를 구하면 MIS 도 O(V + E) 에 구할 수 있습니다. 일반 그래프에서 MIS 는 NP-hard 입니다.

최소 경로 덮개 (Minimum Path Cover, DAG)

DAG 에서 최소 경로 덮개 크기 = |V| - 최대 이분 매칭.

DAG 의 각 정점 v 를 v_out (왼쪽) 과 v_in (오른쪽) 으로 분리하고, 간선 (u, v) 를 (u_out, v_in) 으로 변환하면 이분 그래프가 됩니다.

Max Flow Min Cut (MFMC)

Max Flow Min Cut 정리 와 König’s Theorem 은 같은 원리입니다. 이분 매칭을 최대 유량으로 모델링하면 최소 컷 = 최소 정점 덮개가 됩니다.

함정

WARNING

구현 시 자주 발생하는 실수들.

1. 일반 그래프에 König 적용

König’s Theorem 은 이분 그래프에서만 성립합니다. 일반 그래프에서는 최대 매칭 크기 != 최소 정점 덮개 크기입니다.

2. 교대 경로 BFS 방향

BFS 는 비매칭 왼쪽 정점 에서 시작합니다. 비매칭 오른쪽 정점에서 시작하면 틀립니다.

3. MVC 구성 공식

MVC = (Left \ visitedL) ∪ visitedR 입니다. visitedL 이 아니라 Left 전체에서 visitedL 을 빼야 합니다.

4. 최대 독립 집합과 혼동

MVC 와 MIS 는 서로 보완 관계입니다. MVC 에 속하지 않는 정점들이 MIS 입니다. 두 집합을 혼동하지 마세요.

5. 방향 그래프

방향 그래프에서 vertex cover 는 정의가 다릅니다. 방향 그래프의 최소 경로 덮개는 별도 알고리즘이 필요합니다.

BOJ 연습 문제

번호제목설명
BOJ 1867돌멩이 제거최소 정점 덮개 = 최대 이분 매칭
BOJ 2051최소 버텍스 커버König’s Theorem 직접 적용
BOJ 1298노트북의 주인을 찾아서이분 매칭 기본
BOJ 11375열혈강호이분 매칭 응용

관련 위키

이 글의 용어 (6개)
[Graph] 매칭 (Matching)algorithm
정의 그래프 $G = (V, E)$ 에서 매칭 (Matching) 은 간선의 부분집합 $M \subseteq E$ 이면서 어느 두 간선도 공통 정점을 공유하지 않는 것. - 각 …
이분 그래프 (Bipartite Graph)algorithm
정의 이분 그래프 (Bipartite Graph) 는 정점 집합 V 를 두 개의 독립 집합 L, R 로 분할할 수 있고, 모든 간선이 L 과 R 을 잇는 그래프. 같은 집합 내 …
이분 매칭 (Bipartite Matching)algorithm
정의 이분 매칭 (Bipartite Matching) 은 이분 그래프 G = (L ∪ R, E) 에서 간선 부분집합 M ⊆ E 을 선택하되, M 의 어떤 두 간선도 정점을 공유하…
최대 유량 최소 컷 정리 (Max-Flow Min-Cut Theorem)algorithm
정의 최대 유량 최소 컷 정리 (Max-Flow Min-Cut Theorem) 는 네트워크 유량 그래프 G = (V, E) 에서 source s 에서 sink t 로의 최대 유량…
홀의 결혼 정리 (Hall's Marriage Theorem)algorithm
정의 홀의 결혼 정리 (Hall's Marriage Theorem) 는 이분 그래프 G = (L, R, E) 에서 완전 매칭 (perfect matching) 이 존재할 필요충분…
Maximum Flow: Ford-Fulkerson, Edmonds-Karp, Dinicalgorithm
정의 Maximum Flow (최대 유량) 문제는 방향 그래프 $G = (V, E)$ 와 소스 $s$, 싱크 $t$ 가 주어졌을 때, 각 간선의 용량 제약 아래에서 $s$ 에서 …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기