最大流学习笔记

这里主要介绍一下Dinic算法。。
先介绍几个概念。。
层次图
层次图,就是把原图中的点按照点到源的距离分“层”,只保留不同层之间的边的图。
算法流程
1、根据残量网络计算层次图。
2、在层次图中使用DFS进行增广直到不存在增广路。
3、重复以上步骤直到无法增广。
因为在Dinic的执行过程中,每次重新分层,汇点所在的层次是严格递增的,而n个点的层次图最多有n层,所以最多重新分层n次。在同一个层次图中,因为每条增广路都有一个瓶颈,而两次增广的瓶颈不可能相同,所以增广路最多m条。搜索每一条增广路时,前进和回溯都最多n次,所以这两者造成的时间复杂度是O(nm);而沿着同一条边(i,j)不可能枚举两次,因为第一次枚举时要么这条边的容量已经用尽,要么点j到汇不存在通路从而可将其从这一层次图中删除。综上所述,Dinic算法时间复杂度的理论上界是O(n^2*m)。
附上模板代码:

#include
#include
#include
using namespace std;
int f[201][201],head,tail,dis[201],ans=0,sum=0,n,m,i,x,y,w,q[201];

int bfs()
{
    int j,p;
    memset(dis,-1,sizeof(dis));
    dis[1]=0;
    head=0;
    tail=1;
    q[1]=1;
    while (headq[head];
        for (j=1;j<=n;j++)
          if (dis[j]<0 && f[p][j]>0)
            {
              dis[j]=dis[p]+1;
              tail++;
              q[tail]=j;
            }
      }
    if (dis[n]>0)
      return 1;
    else
      return 0;
}

int dfs(int s,int low)
{
    int j,a=0;
    if (s==n)
      return low;
    for (j=1;j<=n;j++)
      if (f[s][j]>0 && dis[j]==dis[s]+1 && (a=dfs(j,min(low,f[s][j]))))
        {
            f[s][j]-=a;
            f[j][s]+=a;
            return a;
        }
    return 0;
}

int main()
{
    while (scanf("%d %d",&m,&n)!=EOF)
      {
        memset(f,0,sizeof(f));
        for (i=1;i<=m;i++)
          {
            scanf("%d %d %d",&x,&y,&w);
            f[x][y]+=w;
          }
        ans=0;
        while (bfs())
          while (sum=dfs(1,0x7fffffff))
            ans+=sum;
        printf("%d\n",ans);
      }
    return 0;
}

你可能感兴趣的:(最大流)