文章目录
概念
网络流图
若有向图 G = ( V , E ) G=(V,E) G=(V,E)满足:
- 有且仅有一个顶点 S S S,它的入读为 0 0 0,即 d − ( S ) = 0 d-(S) = 0 d−(S)=0,这个顶点S便称为源点。
- 有且仅有一个顶点 T T T,它的出度为 0 0 0,即 d + ( T ) = 0 d+(T) = 0 d+(T)=0,这个顶点T便称为汇点。
- 每一条弧都有非负数,叫做这个边的容量。边
(
v
i
,
v
j
)
(vi,vj)
(vi,vj)的容量用
C
i
j
Cij
Cij表示
则称之为网络流图,记为 G = ( V , E , C ) G = (V,E,C) G=(V,E,C)
可行流
用 f f fi,j表示从 i i i到 j j j的流量,满足:
- 没一条弧 ( i , j ) (i,j) (i,j)有 f f fi,j < = C <= C <=Ci,j
- 流量平衡:除源点和汇点以外的所有点 v i vi vi,有 Σ Σ Σj f f fi,j = Σ = Σ =Σk f f fj,k
- 对于源点 S S S和汇点 T T T有, Σ i f Σif ΣifS,i = Σ j f = Σjf =Σjfj,T = v ( f ) = v(f) =v(f)
可改进路(增广路)
找到一条路径,使原来 S − > T S->T S−>T的流量增加。
残留网络
由残留的容量(边的容量减去可行流)以及源点汇点构成的网络。
割
在容量网络 G ( V , E ) G(V, E) G(V,E) 中, 设 E ′ ⊆ E E'⊆E E′⊆E, 如果在 G G G 的基图中删去 E ′ E' E′ 后不再连通, 则称 E ′ E' E′ 是 G G G 的割。割将 G G G 的顶点集 V V V 划分成两个子集 S S S 和 T = V − S T = V - S T=V−S。将割记为 ( S , T ) (S, T) (S,T)。
基本理论
- 对于 S − T S-T S−T一个可行流 f , f f,f f,f一定小于割的容量。
- 可行流f是最大流的充分必要条件是:残留网络中不存在可改进流量。
- 最大流最小割定理 - 最大流等于最小割
求最大流思路
FF方法
- 初始化网络中各个边的容量, c < u , v > c<u,v> c<u,v>为该边的容量, c < u , v > c<u,v> c<u,v>为初始化0。
- 在残留网络中找到一条 s s s到 t t t的增广路。能找到到3,不能到5
- 在增广路中找到容量最小的边记为 x x x,加到最大流中。
- 在增广路中所有边的流量减去 x x x,反向边加上 x x x,构成新的残留网络,转到2
- 得到最大流。
EK算法
int EK(int s,int t){
int flow = 0 ;
while(1){
memset(a,0,sizeof a);
queue<int> q;
q.push(s);
a[s] = inf;
while(!q.empty()){
int u = q.front();q.pop();
for(int i = h[u];~i;i=ne[i]){
int y = e[i];
if(!a[y] && w[i] > 0){
a[y] = min(a[u],w[i]);
pre[y] = i;
q.push(y);
}
}
if(a[t])break;
}
if(!a[t])break;
for(int i = t;i!=s;i=e[pre[i]^1]){
w[pre[i]] -= a[t],w[pre[i]^1] += a[t];
}
flow += a[t];
}
return flow;
}
dinic
bool dfs(int s,int t){
memset(st,0,sizeof st);
memset(d,inf,sizeof d);
queue<int> q;
q.push(s);
st[s] = true;
d[s] = 0;
while(!q.empty()){
int u = q.front();q.pop();
st[u] = false;
for(int i = h[u];~i;i=ne[i]){
int y = e[i];
if(w[i] > 0 && d[y] > d[u] + 1){
d[y] = d[u] + 1;
if(!st[y])q.push(y);
}
}
}
return d[t] != inf;
}
int bfs(int s,int mw,int t){
if(s == t)return mw;
for(int &i = cur[s];~i;i=ne[i]){
int y = e[i];
if(w[i] <= 0 || d[y] != d[s] + 1)continue;
int cw = bfs(y,min(mw,w[i]),t);
if(cw <= 0)continue;
w[i] -= cw;
w[i^1] += cw;
return cw;
}
return 0;
}
int dinic(int s,int t){
int flow = 0;
while(dfs(s,t)){
memcpy(cur,h,sizeof h);
while(int d = bfs(s,inf,t)) flow += d;
}
return flow;
}
最小费用最大流
保证S-T流量最大的情况下,所需费用最小。
EK+spfa
bool spfa(int s,int t){
for(int i = 1;i<N;i++)dist[i] = inf,d[i] = 0,st[i] = 0;
dist[s] = 0,d[s] = inf,st[s] = true;
queue<int> q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
st[u] = false;
for(int i = h[u];~i;i=ne[i]){
int y = e[i];
if(f[i] && dist[y] > dist[u] + w[i]){
dist[y] = dist[u] + w[i];
d[y] = min(d[u],f[i]);
pre[y] = i;
if(!st[y]){
q.push(y);
st[y] = true;
}
}
}
}
return dist[t] != inf;
}
int EK(int s,int t){
int cost = 0,flow = 0;
while(spfa(s,t)){
for(int i = t;i!=s;i=e[pre[i]^1]){
f[pre[i]] -= d[t];
f[pre[i]^1] += d[t];
}
//根据条件改变
cost += dist[t]*d[t];
flow += d[t];
}
return cost,flow;
}
例 题
poj Power Network
题目链接
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
//526526
using namespace std;
const int N=310,M = 3e4+10,inf = 0x3f3f3f3f;
int h[N],ne[M],e[M],f[M],idx;
int d[N];
void add(int a,int b,int c){
ne[idx] = h[a],e[idx] = b,f[idx] = c,h[a] = idx++;
ne[idx] = h[b],e[idx] = a,f[idx] = 0,h[b] = idx++;
}
int cur[N];
bool st[N];
int n,n1,n2,m;
int a[N],pre[N];
int S = 101,T=102;
/*
int EK(){
int flow = 0;
while(1){
memset(a,0,sizeof a);
queue<int> q;
q.push(S);
a[S] = inf;
while(!q.empty()){
int u = q.front();q.pop();
for(int i = h[u];~i;i=ne[i]){
int y = e[i];
if(!a[y] && f[i] > 0){
a[y] = min(a[u],f[i]);
pre[y] = i;
q.push(y);
}
}
if(a[T])break;
}
if(!a[T])break;
for(int i = T;i!=S;i=e[pre[i]^1]){
f[pre[i]] -= a[T];
f[pre[i]^1] += a[T];
}
flow += a[T];
}
return flow;
}
*/
bool dfs(int s,int t){
memset(st,0,sizeof st);
memset(d,inf,sizeof d);
queue<int> q;
q.push(s);
st[s] = true;
d[s] = 0;
while(!q.empty()){
int u = q.front();q.pop();
st[u] = false;
for(int i = h[u];~i;i=ne[i]){
int y = e[i];
if(f[i] > 0 && d[y] > d[u] + 1){
d[y] = d[u] + 1;
if(!st[y])q.push(y);
}
}
}
return d[t] != inf;
}
int bfs(int s,int mw,int t){
if(s == t)return mw;
for(int &i = cur[s];~i;i=ne[i]){
int y = e[i];
if(f[i] <= 0 || d[y] != d[s] + 1)continue;
int cw = bfs(y,min(mw,f[i]),t);
if(cw <= 0)continue;
f[i] -= cw;
f[i^1] += cw;
return cw;
}
return 0;
}
int dinic(int s,int t){
int flow = 0;
while(dfs(s,t)){
memcpy(cur,h,sizeof h);
while(int d = bfs(s,inf,t)) flow += d;
}
return flow;
}
int main(){
while(cin >> n >> n1 >> n2 >> m){
idx = 0;
memset(h,-1,sizeof h);
int a,b,c;
char t ;
for(int i = 1;i<=m;i++){
cin >> t >> a >> t >> b >> t >> c;
add(a,b,c);
}
for(int i = 1;i<=n1;i++){
cin >> t >> a >> t >> b;
add(S,a,b);
}
for(int i = 1;i<=n2;i++){
cin >> t >> a >> t >> b;
add(a,T,b);
}
cout << dinic(S,T) << endl;
}
return 0;
}