最大流算法模板:EK和dinic算法

最大流算法模板:EK和dinic算法

一、EK算法模板

#include<iostream>
#include<queue>
using namespace std;
const int maxn=205;
const int inf=0x7fffffff;
//图
int r[maxn][maxn]; 
//被访问点为true否则为false
bool visit[maxn];
//pre[i] = j i点之前的点为j点
int pre[maxn];
int m,n;

bool bfs(int s,int t) //寻找一条从s到t的增广路,若找到返回true
{
    int p;
   queue<int > q;
   memset(pre,-1,sizeof(pre));
   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])
           {
               pre[i]=p;
               visit[i]=true;
               if(i==t) return true;
               q.push(i);
           }
       }
    }
    return false;
}

int EdmondsKarp(int s,int t)
{
   int flow=0,d,i;
   //直到一条增广路也找不到就退出
   while(bfs(s,t))
   {
      d = inf;
      //遍历找出当前增广路的最小流量
      for(i=t;i!=s;i=pre[i])
          d = r[pre[i]][i] > d? d:r[pre[i]][i];
      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("%d\n",EdmondsKarp(1,n));
    }
    return 0;
}

二.dinic算法模板

这篇博客写的很好有图有注释
https://www.cnblogs.com/SYCstudio/p/7260613.html
int s,t;//源点和汇点
int cnt;//边的数量,从0开始编号。
int Head[maxN];//每一个点最后一条边的编号
int Next[maxM];//指向对应点的前一条边
int V[maxM];//每一条边指向的点
int W[maxM];//每一条边的残量
int Depth[maxN];//分层图中标记深度
int Dinic()
{
    int Ans=0;//记录最大流量
    while (bfs())
    {
        while (int d=dfs(s,inf))
            Ans+=d;
    }
    return Ans;
}
bool bfs()
{
    queue<int> Q;//定义一个bfs寻找分层图时的队列
    while (!Q.empty())
        Q.pop();
    memset(Depth,0,sizeof(Depth));
    Depth[s]=1;//源点深度为1
    Q.push(s);
    do
    {
        int u=Q.front();
        Q.pop();
        for (int i=Head[u];i!=-1;i=Next[i])
            if ((W[i]>0)&&(Depth[V[i]]==0))//若该残量不为0,且V[i]还未分配深度,则给其分配深度并放入队列
            {
                Depth[V[i]]=Depth[u]+1;
                Q.push(V[i]);
            }
    }
    while (!Q.empty());
    if (Depth[t]==0)//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
        return 0;
    return 1;
}
int dfs(int u,int dist)//u是当前节点,dist是当前流量
{
    if (u==t)//当已经到达汇点,直接返回
        return dist;
    for (int i=Head[u];i!=-1;i=Next[i])
    {
        if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))//注意这里要满足分层图和残量不为0两个条件
        {
            int di=dfs(V[i],min(dist,W[i]));//向下增广
            if (di>0)//若增广成功
            {
            	//为什么异或1 举个例子:输入第一条边编号为0,反向边编号为1,0 ^ 1 = 1, 1 ^ 1 = 0,可以看出进行异或1操作后可以马上得出当前边的反向边,这算是一个小技巧
                W[i] -= di;//正向边减
                W[i^1] += di;//反向边加
                return di;//向上传递
            }
        }
    }
    return 0;//否则说明没有增广路,返回0
}

总结

EK算法的时间复杂度为O(m*m*n),dinic算法的时间复杂度为(n*n*m),其中m代表边数,n代表顶点数。由此可见对于稠密图来说dinic算法更加高效,当然dinic算法还有可以优化的地方,例如当前弧优化,读者可自行查阅资料。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值