문제


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


풀이


완전 중요한 간선을 판별하는 법만 생각해 내면 구현은 어렵지 않은 편이다.

어떤 간선 (a, b)가 완전 중요한 간선이려면, 마지막 상태의 flow network에서 (a, b)에 흐르는 flow와 capacity가 동일해야 한다.

이는 graph 배열에서 확인할 수 있다.

그리고 다음과 같은 명제를 증명할 것이다.

간선 (a, b)는 완전 중요한 간선이 아니다. $ \Leftrightarrow $ a에서 b로 flow 1을 보낼 경로가 존재한다.

(a, b)의 capacity를 1 줄였음에도 불구하고 total flow가 그대로라면 ((a, b)가 완전 중요한 간선이 아니라면), a에서 sink까지 가는 (a, b)를 포함하지 않는 경로가 존재한다.

이때 b부터 sink까지 가는 경로의 flow를 따로 감소시키지 않았으므로, b부터 sink까지 최소 1의 flow가 흐르고 있고, 이는 sink부터 b까지 최소 1의 flow를 흘려보낼 수 있음을 의미한다.

그러므로 a부터 b까지 flow 1을 보낼 수 있다.

반대로, a에서 b로 flow 1을 보낼 경로가 존재한다고 가정하자.

그러면 a $ \rightarrow … \rightarrow $ b $ \rightarrow … \rightarrow $ sink 경로로, 우회해서 flow 1을 보내주면 total flow 또한 변함이 없다.

따라서 위 명제는 참이다.

이를 기반으로 a에서 b로 가는 다른 경로를 찾아보고, 없다면 정답을 1 늘려주면 된다.


코드


import sys
from collections import deque

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

    for _ in range(m):
        start, end, capacity = map(int, sys.stdin.readline().split())
        graph[start][end] += capacity
        edge.append((start, end))

    ans = 0
    while True:
        prev = [-1] * (n + 1)
        queue = deque([(1, float('inf'))])
        while queue:
            cur, res = queue.popleft()
            
            if graph[cur][-1]:
                res = min(res, graph[cur][-1])
                prev[-1] = cur
                break
            
            for nxt in range(2, n):
                if (prev[nxt] == -1) and graph[cur][nxt]:
                    prev[nxt] = cur
                    queue.append((nxt, min(res, graph[cur][nxt])))

            if prev[-1] != -1:
                break
        
        if prev[-1] == -1:
            break

        ans += res
        nxt = -1
        while True:
            cur = prev[nxt]
            graph[cur][nxt] -= res
            graph[nxt][cur] += res
            nxt = cur
            if nxt == 1:
                break

    sol = 0
    for a, b in edge:
        if graph[a][b] == 0:
            prev = [-1] * (n + 1)
            queue = deque([a])
            while queue:
                cur = queue.popleft()
                
                for nxt in range(1, n + 1):
                    if (cur == a) and (nxt == b):
                        continue

                    if (nxt == b) and graph[cur][b]:
                        prev[b] = cur
                        break

                    if (prev[nxt] == -1) and graph[cur][nxt]:
                        prev[nxt] = cur
                        queue.append(nxt)

                if prev[b] != -1:
                    break
            
            if prev[b] == -1:
                sol += 1
    
    print(sol)

Leave a comment