zoukankan      html  css  js  c++  java
  • 最大流问题

    问题描述:

    最大流问题的一个基本描述:如下图所示,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
  • 相关阅读:
    < java.lang >-- StringBuilder字符串缓冲区
    Integer对象
    < java.lang >-- StringBuffer字符串缓冲区
    < java.lang >-- String字符串
    单例设计模式:★★★★★
    线程同步 Lock接口
    POJ 3254 Corn Fields (状压dp)
    Codeforces 583D. Once Again... (LIS变形)
    Light oj 1005
    Codeforces 543D. Road Improvement (树dp + 乘法逆元)
  • 原文地址:https://www.cnblogs.com/kinthon/p/4507719.html
Copyright © 2011-2022 走看看