网络流--最大流问题

一、什么是最大流问题

  简单来说,就是在有向网络图中,单位时间内,从开始点到结束点能通过的最大流量

  许多应用都包含了流量问题,例如,公路系统中有车辆流,控制系统中有信息流,供水系统中有水流,金融系统中有现金流等等

二、简单概念

1、源点:出发点。

2、汇点:结束点。

3、流:就是一条可以从源点到汇点的一条合法路径。

4、容量:每条边都有一个容量(水管的最大水流容量)

5、流量:就是一条可以从源点到汇点的一条合法路径能通过的最大数量,大小取决于这条路径上的最小容量

6、增广路:也就是流,一条可以从源点到汇点的一条合法路径

7、残量:就是剩余容量,对于一条边来说,残量=容量-流量

三、求最大流的过程

下图是一个交通运输网络,有1到6共6个结点,两个结点间的数字代表它们之间的最大运输能力,求结点1到结点6在单位时间内的最大运输能力(流量)?

 

可以看到结点1到结点6之间有多条路径,而所有路径的最大流量之和正是所要求的最大流量,问题转化为求每条路径的最大流量,以路径:1-3-5-6为例,结点间的运输流量分别是10、14、21,容易想到10是这条路径的瓶颈,所以1-3-5-6的最大运行能力是10。同时也意味着,当1-3之间达到运输瓶颈10时,1-3这条路就不再具备运输能力了(就可以把1-3条路从图中去掉了,同时也要把3-5-6路径上的运输能力减掉10,因为已经被我们找到的第一条路径给占用了10,这样就有了下图),记录下第一条路径的最大流量10。

 

下面继续找一条路径:1-2-5-6,它的剩余最大流量是6。按照上面的方法去掉1-2,并把2-5-6的运输能力减6,就有了下图:


 

接下来是:1-4-6,它的剩余最大流量是5。

 

接下来是:1-4-3-5-6,它的剩余最大流量是1。

接下来是:1-4-2-5-6,它的剩余最大流量是1。

 

至此结点1到6之间已经没有通路了,把各个路径的最大流量和加起来即是所求:10+6+5+1+1=23


以上转载自:https://www.jianshu.com/p/e4548c5c381e
 

 

反向边的概念

  当bfs找到的路径不是最优解的时候,我们需要一个反悔机制,返回原来状态去选择另一种合法路径,所以用反向边的概念来解决这个问题。
即每条边(i,j)都有一条反向边(j,i), 反向边也同样有它的容量及流量,且初始的流量值就是为正向边的容量
 

                                                                              

四、代码实现(EK算法)

时间复杂度:O(n*m2),m是边数,n是顶点数量

注意:在读入边的时候,要注意重边的情况,要用加法存边

int flow[205][205],cap[205][205];//flow当前流量,cap总容量
int f[205],vis[205];//f[i]最小残量=cap-flow,vis[i]标记i节点的上一个最小残量所在的位置
int mx_flow;//最大流量,所有增广路最小残量之和
void bfs(int n)
{
    queue<int>p;
    mx_flow=0;
    int flag=0;
    memset(flow,0,sizeof(flow));
    while(flag==0)
    {
        memset(f,0,sizeof(f));
        memset(vis,0,sizeof(vis));
        f[1]=mx,vis[1]=-1;//初始化源点
        p.push(1);
        while(!p.empty())//bfs找增广路
        {
            int now=p.front();
            p.pop();
            for(int i=1;i<=n;i++)
            {
                if(!f[i]&&flow[now][i]<cap[now][i])
                {
                    f[i]=min(f[now],cap[now][i]-flow[now][i]);//取最小残量
                    vis[i]=now;
                    p.push(i);
                }
            }
        }
        if(f[n]==0)//容量-流量==0,一条增广路寻找结束
            flag=1;
        mx_flow+=f[n];
        int pos=n;//从汇点开始更新流量
        while(!flag&&pos!=1)
        {
            flow[vis[pos]][pos]+=f[n];//正向更新流量
            flow[pos][vis[pos]]-=f[n];//反向更新流量
            pos=vis[pos];
        }
    }
}
 

 模板题:https://www.cnblogs.com/-citywall123/p/11322765.html

猜你喜欢

转载自www.cnblogs.com/-citywall123/p/11322771.html