문제


https://www.acmicpc.net/problem/2051


풀이


minimal vertex cover를 직접 구하는 문제이다.

구하는 과정은 Kőnig’s Theorem의 증명 과정을 참고했다.

결론만 얘기하자면 최대 매칭을 구했을 때, minimal vertex cover는 다음 노드들로 구성된다.

  • 왼쪽 노드 중 최대 매칭에 포함되지 않는 노드

  • 이 노드들에서 시작해서, alternating path를 통해 도달할 수 있는 오른쪽 노드

여기서 alternating path란, 최대 매칭에 포함되지 않는 노드에서 출발하여, 최대 매칭에 속하지 않는 엣지, 최대 매칭에 속하는 엣지를 번갈아 선택하는 경로이다.


코드


import sys


def dfs(cur):
    visit[cur] = 1
    for nxt in graph[cur]:
        if not b[nxt] or (not visit[b[nxt]] and dfs(b[nxt])):
            a[cur] = nxt
            b[nxt] = cur
            return 1
    return 0


n, m = map(int, sys.stdin.readline().split())
graph = [[] for _ in range(n + 1)]

for i in range(1, n + 1):
    data = list(map(int, sys.stdin.readline().split()))
    for j in range(1, data[0] + 1):
        graph[i].append(data[j])

a = [0] * (n + 1)
b = [0] * (m + 1)
ans = 0

for i in range(1, n + 1):
    visit = [0] * (n + 1)
    ans += dfs(i)

left = [0] * (n + 1)
right = [0] * (m + 1)

queue = []
for i in range(1, n + 1):
    if not a[i]:
        queue.append((i, 0))
        left[i] = 1

while queue:
    cur, flag = queue.pop()
    
    if flag:
        nxt = b[cur]
        if not left[nxt]:
            left[nxt] = 1
            queue.append((nxt, 0))
    else:
        for nxt in graph[cur]:
            if not right[nxt] and a[cur] != nxt:
                right[nxt] = 1
                queue.append((nxt, 1))

print(ans)
res_left = []
res_right = []

for i in range(1, n + 1):
    if not left[i]:
        res_left.append(i)

for j in range(1, m + 1):
    if right[j]:
        res_right.append(j)


print(len(res_left), *res_left)
print(len(res_right), *res_right)

Leave a comment