最大流问题

问题描述:

最大流问题的一个基本描述:如下图所示,s是源点,t为汇点,每条边上数字的含义是边能够允许流过的最大流量。可以将边看成管道,0/3代表该管道每秒最多能通过3个单位的流量,0代表当前流量。最大流问题即是说,从s点到t点,最大允许流量是多少?

相关算法:

Let G(V,E) be a graph, and for each edge from u to v, let c(u,v) be the capacity and f(u,v) be the flow. We want to find the maximum flow from the source s to the sink t. After every step in the algorithm the following is maintained:

This means that the flow through the network is a legal flow after each round in the algorithm. We define the residual network G_f(V,E_f) to be the network with capacity c_f(u,v) = c(u,v) - f(u,v) and no flow. Notice that it can happen that a flow from v to u is allowed in the residual network, though disallowed in the original network: if f(u,v)>0 and c(v,u)=0 then c_f(v,u)=c(v,u)-f(v,u)=f(u,v)>0. Algorithm Ford–Fulkerson:

The path in step 2 can be found with for example a breadth-first search or a depth-first search in G_f(V,E_f). If you use the former, the algorithm is called Edmonds–Karp(EK).be found, s will not be able to reach t in the residual network. If S is the set of nodes reachable by s in the residual network, then the total capacity in the original network of edges from S to the remainder of V is on the one hand equal to the total flow we found from s to t, and on the other hand serves as an upper bound for all such flows. This proves that the flow we found is maximal. See also Max-flow Min-cut theorem.

以上来自维基百科
总的来说,算法的思想是比较清晰的,就是说我们每次都在残量图中尝试找到一条新的增广路,并取这条增广路上的最小的残量做为新的将流入的流量,并用这个残量更新残量图(也就是把每边的流量更新)。找增广路的方法,可以用bfs,也就是使用queue来找(直接画一个图就理解为什么要用queue了,dfs是用stack,记住找过的点都是要标记的,且不会重复进入queue),每次都找出一条有最短残量的增广路

代码:

queue<int> q;
memset(flow, o, sizeof(flow); //零流
f = 0; //保存当前总流量
while(1) {
  memset(a, o, sizoeof(a));
  a[s] = INF;
  q.push(s);
  while(!q.empty()) { //bfs 找增广路
    int u = q.front();
    q.pop();
    for(int v = 1; v <= n; v++) {
      if(!a[v] && cap[u][v] > flow[u][v]) { //已经找过的点就不用再找了, a[v]同时直到了标记的作用,找新结点
        p[v] = u; //记录V的父亲,后面要用于反向更新流量图
        q.push(v);
        a[v] = a[u] < cap[u][v] - flow[u][v] ? a[u] : cap[u][v] - flow[u][v]; //找S-V上的最小的残量
       }
    }
  }
  if(a[t] = 0) //已经没有增广路了
    break;
  //并不是所有的两个点之间都有正向和反向,只有当两个点之间有两个方向的注入时才有,可以在初始化时,把没有的方向修改了容量为0
  for( int u = t; u != s; u = p[u]) {
    flow[p[u]][u] += a[t]; //更新正向流量 要保证满足注入这个点的流量等于输出这个点的流量
    flow[u][p[u]] -= a[t]; //更新反向流量
  }
  f += a[t];
}

参考网站:

http://blog.csdn.net/smartxxyx/article/details/9293665/

http://en.wikipedia.org/wiki/Ford–Fulkerson_algorithm
原文地址:https://www.cnblogs.com/kinthon/p/4507719.html