实现最大流有好几种算法,比如Dinic或者ISAP算法,Edmonds-Karp只是其中最好理解的一种算法,它的实现要运用到增广路与BFS,当然也可以用DFS,但效率太低。网络流这东西是用来求从s点到t点(起点为s,终点为t)的流量问题,因为类似网络数据传输,所以叫做网络流。
最大流说简单点就是使从s到t的流量最大。这玩意儿需要注意三个事实(起点为s,终点为t):
BFS是普及组必须掌握的,就不多讲了。以下是一些基本知识(有些东西在后面会简写,所以注意一下):
1.容量(c),每条边最大运输量。
2.流量(f),当前用了的运输量。
3.残量网络,即每一条路上容量与流量之差,必须为正数,注意,若a->b的c为16,f为10,在残量网络中a->b为6还有一条边,b->a为10,有两条边!因为可以当做b->a为容量0,流量-11。例如图(a)的残量网络为图(b)(前一个数为流量,后一个数为容量)。
4.增广路,每次在图中找到一条满足上述基本事实的一条从s到t的路(这里用BFS找),这条路上贡献的流量就是其最小残量,每次找到一条路,就让答案加上最小残量,当没有增广路时,可以证明答案即为最优。
下面贴上代码:
#include<queue> #include<cstdio> #include<vector> #include<cstring> #define maxn 1005 #define INF 2147483647 using namespace std; int read(){ int ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } struct Edge{//用来维护每条边的信息 int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct EdmondsKarp{ int n,m,s,t;//n:点数,m:边数,s:起点,t:终点 vector<Edge> edges;//边数开两倍(还有反向网络),这里偷一下懒 vector<int> G[maxn];//领接表,G[i][j]表示点i到延伸出去的第j条边在edges中的位置 int a[maxn];//最小残量,用以增广 int p[maxn];//p[i]表示到达节点i的那条边的编号,因为每次增广只增广一条路径,所以不用开二维 void init(){//不多说,初始化 n=read();m=read();s=read();t=read(); for(int i=0;i<n;i++) G[i].clear(); edges.clear(); for(int i=1;i<=m;i++){ int from=read(),to=read(),cap=read(); edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0));//反向网络 int k=edges.size(); G[from].push_back(k-2); G[from].push_back(k-1); } } int Maxflow(){ int ret=0; while(1){ memset(a,0,sizeof(a)); queue<int> Q;//先进先出的队列 Q.push(s); a[s]=INF; while(!Q.empty()){//里面就是在BFS int x=Q.front();//取队首 Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!a[e.to]/*判环*/&&e.cap>e.flow){ p[e.to]=G[x][i];//记住回去的路 a[e.to]=min(a[x],e.cap-e.flow);//去最小残量 Q.push(e.to); } } if(a[t]) break;//此条路已到达t } if(!a[t]) break;//没有增广路时,即为最大流 for(int u=t;u!=s;u=edges[p[u]].from){//借助p数组倒回去给此次找到的增广路上的每条路的流量都加上最小残量a[t] edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t];//反向网络也要减掉a[t] } ret+=a[t];//答案加上最小残量a[t] } return ret; } }ans; int main(){ freopen("ls.in","r",stdin); ans.init(); printf("%d",ans.Maxflow()); return 0; }
感谢《算法竞赛 入门经典》的图