网络流之最大流

  网络流之前一直尝试去学过好多次,但一直都没搞懂。

  最近一鼓作气终于会最大流的(fuck)

  其实有些时候可能真的一瞬间就理解了些东西(上语文课的时候突然理解增广路了)

  也推荐一些学习的博客(我们不生产资料,我们只是资料的搬运工):

  关于网络流十分形象的解读以及一些基本概念:http://blog.csdn.net/txl199106/article/details/64441994

  关于EK及原理的解释(图很多,虽然有了Dinic要EK也没什么用):https://www.cnblogs.com/zsboy/archive/2013/01/27/2878810.html

  Dinic(讲的很好,结构很好,总之很好):https://www.cnblogs.com/zsboy/archive/2013/01/27/2878810.html

 

  因为我太弱,搞不来图片,用画图又太丑。

  只能草率的讲一讲思想(个人理解)

  

  EK:虽然没什么用,但复杂度还可以接受。

  1.在残量网络中找到一条从S到T的增广路,如果没有则结束该算法。

  2.更新这条路上的边,正向边减,反向边加上最小值即可。

  3.重复1,2

  其实EK还是很简单的,主要是看代码理解一下:

inline int BFS(int s,int t)
{
    memset(pre,-1,sizeof(pre));
    memset(f,0,sizeof(f));
    int H=0,T=1;
    q[1]=s; pre[s]=0; f[s]=1e9;
    while (H<T)
    {
        int now=q[++H];
        for (int i=1;i<=n;++i)
        if (i!=pre[now]&&pre[i]==-1&&c[now][i]>0)
        {
            pre[i]=now;
            f[i]=f[now]<c[now][i]?f[now]:c[now][i];
            q[++T]=i;
        }
    }
    return f[t]?f[t]:-1;
}
inline int max_flow(int s,int t)
{
    memset(f,0,sizeof(f));
    int sum=0,inc;
    while ((inc=BFS(s,t))!=-1)
    {
        int now=t;
        while (now!=s)
        {
            c[pre[now]][now]-=inc;
            c[now][pre[now]]+=inc;
            now=pre[now];
        }
        sum+=inc;
    }
    return sum;
}

 

  Dinic:非常好用的网络流算法,能解决几乎全部的网络流问题。

  同EK相似,只不过加上了分层图的一些概念。

  1.对整张图跑一遍BFS,记录每个点被访问的深度。

  2.通过DFS来找增广路,必须满足被扩展节点的深度为扩展节点深度+1。

  3.重复1,2。

  主要细节有几个:

  1.建边时从0开始编号,每次建两条(一正一反),这样对于每条边i它的反向边就是i^1

  2.如果在DFS时经过一个点已经没有增广路了,那么以后经过该点肯定也没有了。因此直接把深度清零即可。

  3.DFS时最好一次找多条增广路,可以加快速度。

  具体看代码:

inline bool BFS()
{
    memset(dep,0,sizeof(dep));
    dep[s]=1; q[1]=s;
    int H=0,T=1;
    while (H<T)
    {
        int now=q[++H];
        for (int i=head[now];i!=-1;i=e[i].next)
        if (!dep[e[i].to]&&e[i].c)
        {
            dep[e[i].to]=dep[now]+1;
            q[++T]=e[i].to;
        }
    }
    return dep[t];
}
inline int DFS(int now,int dist)
{
    if (now==t) return dist;
    int res=0;
    for (int i=head[now];i!=-1&&dist;i=e[i].next)
    if (dep[e[i].to]==dep[now]+1&&e[i].c)
    {
        int dis=DFS(e[i].to,min(dist,e[i].c));
        dist-=dis; res+=dis;
        e[i].c-=dis; e[i^1].c+=dis;
    }
    if (!res) dep[now]=0;
    return res;
}
inline int Dinic()
{
    int sum=0;
    while (BFS()) sum+=DFS(s,INF);
    return sum;
}

 

  其实网络流难在建模,但要把板子打熟也是很重要的。

posted @ 2018-03-17 11:35  空気力学の詩  阅读(356)  评论(0编辑  收藏  举报