网络流
概念
流网络:原图(无反向边)\(G=(V,E)\),起点为s,终点为t。记 \(c(u,v)\) 为 \(u\) 到 \(v\) 的流量限制。
可行流:记 \(f(u,v)\) 为 \(u\) 到 \(v\) 之间的流量。则可行流 \(f\) 满足以下条件:
- 容量限制:\(0 \leq f(u,v) \leq c(u,v)\)
- 流量守恒:\(\sum f(v,x)=\sum f(x,u)\)
最大流:最大可行流
残量网络:和可行流对应。记为 \(G_f\)。\(V_f=V,E_f=E和E中的所有反向边\)。
\(c'(u,v) = \begin{cases} c(u,v)-f(u,v) & (u,v) \in E \\ f(v,u) & (v,u) \in E \end{cases}\)
增广路径:在残量网络里从起点能达到终点的一条路径。
割:把V分为两个集合S,T,满足\(S \cup T=V,S \cap T=\emptyset\)
- 容量c(S,T):两个集合之间的容量之和。
- 流量f(S,T):对于一种可行流,两个集合之间的流量之和。
- 对于任意可行流f:\(|f|=f(u,v) \leq c(u,v)。\)
- 最小割:最小割的容量。
- 最大流等于最小割
EK
在残量网络中寻找一条增广路,将流量尽可能地流入这条增广路。
重复以上步骤直到没有增广路。
时间复杂度:\(O(|V||E|^2)\),证明见OI Wiki
Dinic
对 EK 进行改进,我们想每次找多条增广路。为了避免形成环,找增广路前需要先对图进行分层,然后再在分层图中找增广路。
时间复杂度:\(O(|V|^2|E|)\),证明见OI Wiki
实际上会比理论上快很多。
int head[N], vi[M], wi[M], ne[M], tot = 1, dis[N], s, t;
queue <int> q;
bool bfs(){
while(!q.empty())
q.pop();
memset(dis, -1, sizeof(dis));
q.push(s);
dis[s] = 0;
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = head[x]; i; i = ne[i]){
int y = vi[i];
if(dis[y] == -1 && wi[i]){
dis[y] = dis[x] + 1;
if(y == t)
return 1;
q.push(y);
}
}
}
return 0;
}
long long dfs(int x, long long lim){
if(x == t)
return lim;
long long flow = 0;
for(int &i = cur[x]; i; i = ne[i]){
int y = vi[i];
if(dis[y] != dis[x] + 1 || !wi[i])
continue;
long long t = dfs(y, min(1ll * wi[i], lim - flow));
if(!t)
dis[y] = -1;
wi[i] -= t, wi[i ^ 1] += t, flow += t;
if(flow == lim)
break;
}
return flow;
}
long long dinic(){
long long sum = 0, flow;
while(bfs()){
memcpy(cur, head, sizeof(head));
while(flow = dfs(s, INF))
sum += flow;
}
return sum;
}
费用流
int head[N], vi[M], wi[M], pr[M], ne[M], tot = 1;
int ss, tt, dis[N], cur[N];
bool inq[N], vis[N];
queue <int> q;
bool spfa(){
memset(dis, 0x3f, sizeof(dis));
memset(inq, 0, sizeof(inq));
while(!q.empty())
q.pop();
dis[ss] = 0, inq[ss] = 1;
q.push(ss);
while(!q.empty()){
int x = q.front();
q.pop();
inq[x] = 0;
for(int i = head[x]; i; i = ne[i]){
int y = vi[i];
if(dis[y] > dis[x] + pr[i] && wi[i]){
dis[y] = dis[x] + pr[i];
if(!inq[y]){
q.push(y);
inq[y] = 1;
}
}
}
}
return dis[tt] != dis[0];
}
int dfs(int x, int lim, int &cst){
if(x == tt)
return lim;
vis[x] = 1;
int flow = 0;
for(int &i = cur[x]; i; i = ne[i]){
int y = vi[i];
if(dis[y] != dis[x] + pr[i] || !wi[i] || vis[y])
continue;
int dlt = dfs(y, min(lim - flow, wi[i]), cst);
flow += dlt, cst += pr[i] * dlt, wi[i] -= dlt, wi[i ^ 1] += dlt;
if(flow == lim)
break;
}
vis[x] = 0;
return flow;
}
int dinic(){
int sum = 0, flow, cst = 0;
while(spfa()){
memcpy(cur, head, sizeof(head));
while((flow = dfs(ss, INF, cst)))
sum += flow;
}
return cst;
}

浙公网安备 33010602011771号