lang:cpp
#include<queue>
#include<cstdlib>
#include<vector>
#include<cassert>
using namespace std;
// Edmonds-Karp 네트워크 플로우 알고리즘의 구현. 원저자: JongMan
// 시간 복잡도: O(V*E*E)
// 공간 복잡도: O(V*V)
// 주의
// 1. 이 클래스는 반드시 힙에 선언할 것! 클래스 크기가 크므로 스택에 선언하면
// 스택 오버플로우가 날 수 있다.
// 2. MAXV 가 실제 정점 개수와 같거나 그보다 큰지 반드시 확인할 것.
class NetworkFlow
{
public:
// 내부 함수 및 변수
// =================
// MAXV 는 최대 정점의 수
enum { MAXV = 210 };
int flow[MAXV][MAXV], cap[MAXV][MAXV], totalFlow, V;
// (a, b) 간선으로 c 만큼의 유량을 보낸다
void push(int a, int b, int c) { flow[a][b] += c; flow[b][a] = - flow[a][b]; }
// (a, b) 간선의 residual capacity 를 반환한다
int res(int a, int b) { return cap[a][b] - flow[a][b]; }
// 인터페이스
// ==========
// V 는 정점의 최대 수
NetworkFlow(int V): V(V)
{
assert(V <= MAXV);
memset(flow, 0, sizeof(flow));
memset(cap, 0, sizeof(cap));
totalFlow = 0;
}
// (a, b) 간선의 capacity 에 c 를 더한다
void addEdge(int a, int b, int c) { cap[a][b] += c; }
// source 로부터 sink 까지 한 번 augmenting path 를 찾아 보내고, 이 path 의 유량을 반환한다
int pushFlow(int source, int sink)
{
vector<int> pred(V, -1); queue<int> q;
q.push(source); pred[source] = source;
while(!q.empty() && pred[sink] == -1)
{
int u = q.front(); q.pop();
for(int v = 0; v < V; ++v) if(res(u,v) > 0 && pred[v] == -1) { pred[v] = u; q.push(v); }
}
if(pred[sink] == -1) return 0;
int h, amt = 2147483647;
h = sink; while(pred[h] != h) { amt = min(amt, res(pred[h], h)); h = pred[h]; }
h = sink; while(pred[h] != h) { push(pred[h], h, amt); h = pred[h]; }
totalFlow += amt;
return amt;
}
// source 로부터 sink 까지의 최대 유량을 반환한다
int go(int source = 0, int sink = 1)
{
int ret = 0, f;
while(f = pushFlow(source, sink))
ret += f;
return ret;
}
};
int main()
{
NetworkFlow* flow = new NetworkFlow(3);
flow->addEdge(0, 1, 7);
flow->addEdge(1, 2, 4);
assert(flow->go(0, 2) == 4);
delete flow;
}