최소 비용 최대 유량 (Min-Cost Max-Flow, MCMF)
정의
최소 비용 최대 유량 (Min-Cost Max-Flow, MCMF) 은 각 간선에 용량(capacity)과 단위 비용(cost)이 주어질 때, 최대 유량을 달성하는 여러 방법 중 총 비용이 최소인 흐름을 구하는 문제.
가장 보편적인 알고리즘: Successive Shortest Augmenting Path (SSP). 각 단계에서 residual graph의 최소 비용 경로를 찾아 유량을 증가시킨다.
문제 상황과 동기
“최소 비용으로 최대 물량 수송”, “최소 비용으로 작업 배정”, “자원 할당 최적화”.
- naive: 가능한 모든 흐름 열거. 지수.
- SSP: 각 augmentation에서 SPFA/Bellman-Ford로 최소 비용 경로 탐색. O(F * E * V) (F = max flow).
핵심 통찰: 각 augmentation에서 항상 현재 residual graph의 최소 비용 경로를 선택하면, 최종 흐름이 전체 최소 비용. 이 greedy가 성립하는 이유는 비용이 선형이고 음수 사이클이 없기 때문.
시각화
핵심 아이디어
Residual graph with cost
원래 간선 (u, v)에 용량 c, 비용 w가 있을 때 residual graph:
- forward edge: 용량 c - f, 비용 w.
- backward edge: 용량 f, 비용 -w (되돌릴 때 비용 회수).
Successive Shortest Augmenting Path (SSP)
flow = 0, cost = 0
while there is s->t path in residual graph:
find min-cost path (SPFA / Dijkstra with potentials)
if no path: break
augment min(bottleneck) units along path
update flow, cost, residual graph
return flow, cost
초기 비용이 음수 없으면 각 augmentation이 최소 비용 경로를 선택하도록 보장.
SPFA (Shortest Path Faster Algorithm)
음수 가중치 허용. backward edge의 비용이 -w이므로 음수 간선 존재 가능. Bellman-Ford 기반이지만 queue로 최적화.
알고리즘
MCMF_SSP(G, s, t):
for each edge (u, v):
f[u][v] = 0
totalFlow = 0, totalCost = 0
while true:
dist, parent = SPFA(G_f, s)
if dist[t] == INF: break
bottleneck = min residual along path
totalFlow += bottleneck
totalCost += bottleneck * dist[t]
update f and residual along path
return totalFlow, totalCost
구현
// MCMF: SSP with SPFA
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1e18;
struct MCMF {
int n;
struct Edge { int v, rev; ll cap, cost; };
vector<vector<Edge>> g;
vector<ll> dist;
vector<int> pv, pe;
MCMF(int n) : n(n), g(n), dist(n), pv(n), pe(n) {}
void addEdge(int u, int v, ll cap, ll cost) {
g[u].push_back({v, (int)g[v].size(), cap, cost});
g[v].push_back({u, (int)g[u].size() - 1, 0, -cost});
}
bool spfa(int s, int t) {
fill(dist.begin(), dist.end(), INF);
fill(pv.begin(), pv.end(), -1);
fill(pe.begin(), pe.end(), -1);
vector<bool> inq(n, false);
queue<int> q; q.push(s);
dist[s] = 0; inq[s] = true;
while (!q.empty()) {
int u = q.front(); q.pop(); inq[u] = false;
for (int i = 0; i < (int)g[u].size(); i++) {
auto& e = g[u][i];
if (e.cap > 0 && dist[e.v] > dist[u] + e.cost) {
dist[e.v] = dist[u] + e.cost;
pv[e.v] = u; pe[e.v] = i;
if (!inq[e.v]) { q.push(e.v); inq[e.v] = true; }
}
}
}
return dist[t] < INF;
}
pair<ll, ll> flow(int s, int t) {
ll flow = 0, cost = 0;
while (spfa(s, t)) {
ll pushed = INF;
for (int v = t; v != s; v = pv[v])
pushed = min(pushed, g[pv[v]][pe[v]].cap);
for (int v = t; v != s; v = pv[v]) {
auto& e = g[pv[v]][pe[v]];
e.cap -= pushed;
g[v][e.rev].cap += pushed;
}
flow += pushed;
cost += pushed * dist[t];
}
return {flow, cost};
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, s, t; cin >> n >> m >> s >> t;
MCMF mcmf(n);
for (int i = 0; i < m; i++) {
int u, v; ll cap, cost;
cin >> u >> v >> cap >> cost;
mcmf.addEdge(u, v, cap, cost);
}
auto [flow, cost] = mcmf.flow(s, t);
cout << flow << " " << cost << "\n";
}4 5 0 3
0 1 2 1
0 2 3 2
1 2 1 3
1 3 3 4
2 3 4 15 19복잡도
| 항목 | 값 |
|---|---|
| 시간 (SSP + SPFA) | O(F * V * E) (F = max flow) |
| 시간 (SSP + Dijkstra + potential) | O(F * (E log V)) |
| 공간 | O(V + E) |
SPFA는 음수 비용 backward edge 처리 가능. Dijkstra는 Johnson potential 필요.
변형 / 활용
1. 최소 비용 최대 유량 vs 최소 비용 유량
MCMF는 최대 유량을 전제. 특정 유량 f0를 목표로 하려면 sink 직전 edge의 용량을 f0로 제한.
2. 이분 매칭 + 비용
왼쪽 L, 오른쪽 R. s->L (1, 0), L->R (1, cost), R->t (1, 0). 최대 매칭 중 최소 비용.
3. 음수 사이클 제거 (Cancel-and-Tighten)
초기 유량이 최적이 아니면 residual graph에 음수 사이클 존재. 사이클 제거로 최적화.
4. Circulation with demands
각 정점에 supply/demand. MCMF로 feasible circulation + 최소 비용.
함정
1. SPFA 무한 루프
음수 사이클이 있으면 SPFA가 무한 루프. 초기 입력에 음수 사이클 없거나, 최대 V번 iteration 제한.
2. 비용 오버플로우
cost * flow가 int 범위를 넘을 수 있음. long long 사용.
3. Dijkstra + potential 초기화
Johnson potential h[v] = shortest distance from s. 각 augmentation 후 h[v] += dist[v]로 갱신. SPFA가 더 간단.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 11405 | 책 구매하기 | (수집 안 됨) | kokoa-lab |
| BOJ 11408 | 열혈강호 5 | (수집 안 됨) | kokoa-lab |
| BOJ 2311 | 왕복 여행 | (수집 안 됨) | kokoa-lab |
| BOJ 11406 | 책 구매하기 2 | (수집 안 됨) | kokoa-lab |
참고
이 글의 용어 (4개)
- 네트워크 유량 (Network Flow)algorithm
- 정의 네트워크 유량 (Network Flow) 은 방향 그래프 G = (V, E) 에서 각 간선 (u, v) 의 용량 (capacity) c(u, v) 가 주어질 때, 소스 s …
- 벨만-포드 알고리즘 (Bellman-Ford Algorithm)algorithm
- 정의 벨만-포드 알고리즘 (Bellman-Ford Algorithm) 은 음수 가중치 간선을 허용하면서 단일 시작점 s 로부터 모든 정점까지의 최단 거리를 찾는 DP 기반 알고리…
- 최대 유량 최소 컷 정리 (Max-Flow Min-Cut Theorem)algorithm
- 정의 최대 유량 최소 컷 정리 (Max-Flow Min-Cut Theorem) 는 네트워크 유량 그래프 G = (V, E) 에서 source s 에서 sink t 로의 최대 유량…
- 헝가리안 알고리즘 (Hungarian Algorithm)algorithm
- 정의 헝가리안 알고리즘 (Hungarian Algorithm) 은 완전 이분 그래프 K{n,n} 에서 최대 (또는 최소) 가중치 완전 매칭 을 O(n^3) 에 찾는 알고리즘. -…
💬 댓글