最大流问题——Ford Fulkerson算法

算法实践课留了自学算法。看了一些资料。
原文链接:https://www.cnblogs.com/kuangbin/archive/2011/07/26/2117636.html?tdsourcetag=s_pctim_aiomsg
原文链接:https://blog.csdn.net/Ivan_zgj/article/details/51580993
现在自己整理一下。

前提引入

1962 年L.R.Ford和D.R.Fulkerson把原始-对偶算法应用于最大流问题,提出最大流问题的标号算法。简称FF算法,下面引入相关概念。

定义

设容量网络N=<V,E,c,s,t>,f是N上的一个可行流。N中流量等于容量的边称作饱和边,流量小于容量的边称作非饱和边,流量等于0的边称作零流边,流量大于0的边称为非零流边。
不考虑边的方向,N中从顶点到i到j的一条边不重复的路径称为i-j链,i-j链的方向是从i到j,链中与链的方向的一致的边称作为前向边,与链的方向相反的边称作后向边,如果链中所有前向边都是非饱和的,所有后向边都是非零流的,则称这条链为i-j增广链。

Ford-Fulkerson算法

Ford-Fulkerson算法为迭代算法,基本思路如下:
首先,对所有结点i,j∈V令f(i,j)=0;
然后,通过迭代方式不断在残留网络中寻找一个增广路径来增加流值,直到残留网络中不包括增广路径为止。
具体地说:
首先,初始化一条容量为0的流f和一个残留网络Nf, 第一个残留网络为原图N,每条边的残留容量初始化为每条边的初始容量: cf(i,j)= c(i,j)。
然后,在残留网络Nf中寻找增广路径P,取增广路径P中的边的残留容量cf(i,j)最小值作为流的增量△f,使得: f’=f+ △ f
最后,修改剩余图中每条边的容量: c’f(i,j)=cf(i,j)- △ f 得到残留网络Nf.
重复上述过程,直到找不到一条增广路径为止

步骤

Ford-Fulkerson方法是一种迭代的计算过程,实现步骤如下:
1.初始化图中流的值;
2.在残存网络中找到增广路径;
3.沿着增广路径增加流的值,直到残存网络不存在增广路径为止

例题


对图中的容量网络应用FF算法,图中边旁的数是容量。
用FF算法的计算过程如下图所示。(同教材175页)

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

算法

Ford-Fulkerson算法
Ford-Fulkerson方法的伪代码如下。其中<u,v>代表顶点u到顶点v的一条边,<u,v>.f表示该边的流量,c是边容量矩阵,c(i,j)表示边<i,j>的容量,当边<i,j>不存在时,c(i,j)=0。e为残存网络矩阵,e(i,j)表示边<i,j>的值,当边<i,j>不存在时,e(i,j)=0。E表示边的集合。f表示流网络。Ford-Fulkerson方法的伪代码如下。其中<u,v>代表顶点u到顶点v的一条边,<u,v>.f表示该边的流量,c是边容量矩阵,c(i,j)表示边<i,j>的容量,当边<i,j>不存在时,c(i,j)=0。e为残存网络矩阵,e(i,j)表示边<i,j>的值,当边<i,j>不存在时,e(i,j)=0。E表示边的集合。f表示流网络。

Ford-Fulkerson

for <u,v> ∈ E

    <u,v>.f = 0

while find a route from s to t in e

    m = min(<u,v>.f, <u,v>  ∈ route)

    for <u,v> ∈ route

        if <u,v>  ∈ f

            <u,v>.f = <u,v>.f + m

        else

            <v,u>.f = <v,u>.f - m

原文链接:https://blog.csdn.net/Ivan_zgj/article/details/51580993
原文链接:https://www.cnblogs.com/kuangbin/archive/2011/07/26/2117636.html?tdsourcetag=s_pctim_aiomsg
最后再放上两个原文链接供学习使用。
代码:

#include<iostream>
#include<queue>
using namespace std;
const int maxn=205;//最大结点数
const int inf=0x7fffffff;

int r[maxn][maxn]; //残留网络,初始化为原图
bool visit[maxn];//是否被访问过
int pre[maxn];//前驱子图,记录了从顶点s到终点的一条可行路径上的其它顶点的前一个顶点,从前驱子图中找到从s到t的一条完整路径
int m,n;//边数,顶点数

bool bfs(int s,int t)  //广度优先寻找一条从s到t的增广路,若找到返回true
{
    int p;
    queue<int> q;//创建一个队列的对象
    memset(pre,-1,sizeof(pre));//初始化,把数组pre中所有元素设置为-1
    memset(visit,false,sizeof(visit));
    pre[s]=s;
    visit[s]=true;
    q.push(s);//把源点放进队列里面
    while(!q.empty())//当队列不为空,继续找下一个结点
    {
        p=q.front();//取出队首
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(r[p][i]>0&&!visit[i])//如果从p出发到其他顶点,有残留容量大于0,并且没有被标记
            {
                pre[i]=p;//记录通路
                visit[i]=true;
                if(i==t) //如果找到汇点就结束
return true;
                q.push(i);//接着将该点进栈
            }
        }
    }
    return false;
}

int EK(int s,int t)//计算最大流
{
   int flow=0,d,i;
   while(bfs(s,t))//当可以找到时
   {
       d=inf;
       for(i=t;i!=s;i=pre[i])
           d=d<r[pre[i]][i]? d:r[pre[i]][i];//找到增广路径中最小流量,如果d<r[pre[i]][i],把d的值赋给d,否则把r[pre[i]][i]的值赋给d
       for(i=t;i!=s;i=pre[i])//顺藤摸瓜找回去,正向,逆向分别更改
       {
           r[pre[i]][i]-=d;//正
           r[i][pre[i]]+=d;//反
       }
       flow+=d;//
   }
   return flow;
}
int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int u,v,w;
        memset(r,0,sizeof(r));//
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            r[u][v]+=w;
        }
printf("最大流:");
        printf("%d\n",EK(1,n));
    }
    return 0;
}
  • 24
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ford-Fulkerson算法最大流问题的一种经典算法。以下是一个基于增广路思想的Ford-Fulkerson算法的代码: ``` // 基于邻接矩阵的Ford-Fulkerson算法实现 #include <iostream> #include <queue> #include <cstring> using namespace std; const int MAXN = 100; // 最大顶点数 const int INF = 0x3f3f3f3f; // 表示无穷大 int n, m; // n表示顶点数,m表示边数 int s, t; // s表示源点,t表示汇点 int cap[MAXN][MAXN]; // 表示容量 int flow[MAXN][MAXN]; // 表示流量 int pre[MAXN]; // 表示前驱节点 int bfs() { memset(pre, -1, sizeof(pre)); // 初始化前驱节点数组 queue<int> q; q.push(s); pre[s] = -2; while (!q.empty()) { int u = q.front(); q.pop(); for (int v = 0; v < n; ++v) { if (pre[v] == -1 && cap[u][v] > flow[u][v]) { pre[v] = u; if (v == t) return 1; q.push(v); } } } return 0; } int maxFlow() { int ans = 0; while (bfs()) { int minflow = INF; for (int u = t; u != s; u = pre[u]) { int v = pre[u]; minflow = min(minflow, cap[v][u] - flow[v][u]); } for (int u = t; u != s; u = pre[u]) { int v = pre[u]; flow[v][u] += minflow; flow[u][v] -= minflow; } ans += minflow; } return ans; } int main() { cin >> n >> m >> s >> t; memset(cap, 0, sizeof(cap)); memset(flow, 0, sizeof(flow)); for (int i = 0; i < m; ++i) { int u, v, c; cin >> u >> v >> c; cap[u][v] += c; // 注意有可能存在重边 } cout << maxFlow() << endl; return 0; } ``` 算法思路: 1. 初始化流量为0; 2. 在剩余容量大于0的情况下,寻找增广路: - 从源点s开始,使用BFS寻找一条增广路; - 如果找到增广路,计算增广路上的最小剩余容量minflow,更新流量; 3. 最大流就是所有增广路上的最小剩余容量之和。 其中,增广路的定义是指从源点到汇点路径上,剩余容量均大于0的路径。在Ford-Fulkerson算法中,每次都需要寻找一条增广路来更新流量,直到无法再找到增广路为止。这个过程中,每次找到的增广路都可以使得流量增加,因此最终的流量是不断增加的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值