zoukankan      html  css  js  c++  java
  • 最大流 基础

                                                  图1

    如图-1所示,在这个运输网络中,源点S和汇点T分别是1,7,各边的容量为C(u,v)。图中红色虚线所示就是一个可行流。标准图示法如图-2所示:

     

    其中p(u,v) / c(u,v)分别表示该边的实际流量与最大容量。

    关于最大流

    熟悉了什么是网络流,最大流也就很好理解了。就是对于任意的u∈V-{s},使得p(s,u)的和达到最大。上面的运输网络中,最大流如图-3所示:MaxFlow=p(1,2)+p(1,3)=2+1=3。

     

    在介绍最大流问题之前,先介绍几个概念:残余网络,增广路径,反向弧,最大流定理以及求最大流的Ford-Fulkerson方法。

    残余网络 增广路径 反向弧

    观察下图-4,这种状态下它的残余网络如图-5所示:

     

     

    也许现在你已经知道什么是残余网络了,对于已经找到一条从S 到T的路径的网络中,只要在这条路径上,把C(u,v)的值更新为C(u,v)-P(u,v),并且添加反向弧C(v,u)。对应的增广路径Path为残留网络上从S到T的一条简单路径。图-4中1,2,4,7就是一条增广路径,当然还有1,3,4,7。

    此外在未做任何操作之前,原始的有向图也是一个残余网络,它仅仅是未做任何更新而已。

    最大流定理

    如果残留网络上找不到增广路径,则当前流为最大流;反之,如果当前流不为最大流,则一定有增广路径。

    Ford-Fulkerson方法
      介绍完上面的概念之后,便可以用Ford-Fulkerson方法求最大流了。为什么叫Ford-Fulkerson方法而不是算法,原因在于可以用多种方式实现这一方法,方式并不唯一。下面介绍一种基于广度优先搜索(BFS)来计算增广路径P的算法:Edmonds-Karp算法。
      算法流程如下:
      设队列Q:存储当前未访问的节点,队首节点出队后,成为已检查的标点;
      Path数组:存储当前已访问过的节点的增广路径;
      Flow数组:存储一次BFS遍历之后流的可改进量;
      Repeat:
        Path清空;
        源点S进入Path和Q,Path[S]<-0,Flow[S]<-+∞;
        While Q非空 and 汇点T未访问 do
            Begin
                队首顶点u出对;
                For每一条从u出发的弧(u,v) do
                    If v未访问 and 弧(u,v) 的流量可改进;
                    Then Flow[v]<-min(Flow[u],c[u][v]) and v入队 and Path[v]<-u;
        End while
       
        If(汇点T已访问)
        Then 从汇点T沿着Path构造残余网络;

      Until 汇点T未被访问 

    模版题:

    POJ 1273 Drainage Ditches 

    代码: 

    View Code 
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <queue>
     5 using namespace std;
     6 const int N=210;
     7 const int INF=0x7FFFFFFF;
     8 int n,m,map[N][N],path[N],flow[N],start,end;
     9 queue<int> q;
    10 int bfs()
    11 {
    12      int i,t;
    13      while(!q.empty()) 
    14          q.pop();
    15      memset(path,-1,sizeof(path));
    16      path[start]=0,flow[start]=INF;
    17      q.push(start);
    18      while(!q.empty())
    19      {
    20          t=q.front();
    21          q.pop();
    22          if(t==end) 
    23              break;
    24          for(i=1;i<=m;i++)
    25          {
    26              if(i!=start&&path[i]==-1&&map[t][i])//找到新节点i
    27              {
    28                  //路径上的最小残量
    29                  flow[i]=flow[t]<map[t][i]?flow[t]:map[t][i];
    30                  q.push(i);//记录i的父亲,并加入FIFO队列
    31                  path[i]=t;
    32              }
    33          }
    34      }
    35      if(path[end]==-1)
    36          return -1;
    37      return flow[m];//一次遍历之后的流量增量
    38 }
    39 int Edmonds_Karp()
    40 {
    41      int max_flow=0,step,now,pre;
    42      while((step=bfs())!=-1)
    43      {//找不到增广路径时退出
    44          max_flow+=step;
    45          now=end;
    46          while(now!=start)
    47          {
    48              pre=path[now];
    49              map[pre][now]-=step;//更新正向边的实际容量
    50              map[now][pre]+=step;//添加反向边
    51              now=pre;
    52          }
    53      }
    54      return max_flow;
    55 }
    56 int main()
    57 {
    58      int i,u,v,cost;
    59      while(~scanf("%d%d",&n,&m))
    60      {
    61          memset(map,0,sizeof(map));
    62          for(i=0;i<n;i++)
    63          {
    64              scanf("%d%d%d",&u,&v,&cost);
    65              map[u][v]+=cost;
    66          }
    67          start=1,end=m; 
    68          printf("%d\n",Edmonds_Karp());
    69      }
    70      return 0;
    71 }
    72
  • 相关阅读:
    Django:同一个app支持多个数据库
    Django部署以及整合celery
    软件破解码等
    操作日志的设计小结by大熊
    用户-权限-组织-三员分立
    mysql调优
    笔试面试中常见的位运算用法
    Ubuntu系统下搭建Java平台
    All about Oracle Character Set
    各位技术大牛们的逆袭集锦!屌丝们都看过来!
  • 原文地址:https://www.cnblogs.com/pony1993/p/2612883.html
Copyright © 2011-2022 走看看