初学网络流

初学网络流

这个主题以前没接触过,觉得有点抽象,算法有点不太清楚,看了一些博客,下面,对这些博客做些总结。

引入:

具体参考这篇博客的背景知识讲解部分(具体到代码之前),首先对网络流有了一个初步的印象

https://blog.csdn.net/wzw1376124061/article/details/55001639

然后一些概念性的定义,具体参考这篇博客,对一些可能会影响到算法理解的基础概念进行掌握

https://www.cnblogs.com/widerg/p/9387909.html

算法:

然后接触到算法,显示FF(Ford-Fulkerson)算法的思想,用的是dfs,主要理解增加的反向边和算法的流程。然后是EK算法,也是上面一篇博客

对算法大致了解后可以看看实例,上面一篇博客的图是个理解负向边很好的例子,加上这篇博客

https://www.cnblogs.com/zsboy/archive/2013/01/27/2878810.html结合算法对实例的分析

代码:

下面就可以看代码了,主要是这几篇博客比较清晰:

https://blog.csdn.net/wzw1376124061/article/details/55001639

https://www.cnblogs.com/widerg/p/9387909.html

总结与拓展:

最后的总结这篇博客更适合:https://www.cnblogs.com/rvalue/p/10650849.html,分析的比较细,虽然我还不太真正的明白在讲些什么,但估计熟悉以后就会明白了吧

如果还想更高级的dinic算法,也是上一篇博客,加上这个https://baijiahao.baidu.com/s?id=1612179096991409044&wfr=spider&for=pc,讲解的比较清楚

模板:

//Edmonds Karp
#include <iostream>
#include <vector>
#include <queue>
#include <memory.h>
#define maxn 1005
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct EdmondsKarp
{
    int n,m;
    vector<Edge> edges;//保存各个边的信息,包括反向边
    vector<int> G[maxn];//G[i][j]表示第i个节点的第j条边在edges中的编号
    int a[maxn];//起点到i的可改进量
    int p[maxn];//最短路树p的入弧编号
    void init(int n)
    {
        for(int i = 0;i<n;i++)
        {
            G[i].clear();
        }
        edges.clear();
    }
    void AddEdge(int from,int to,int cap)
    {
        edges.push_back(Edge(from,to,cap,0));//edges中的第m-2号边,目前的倒数第二个
        edges.push_back(Edge(to,from,0,0));//反向边,edges中的第m-1号边,目前的最后一个
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    int Maxflow(int s,int t)
    {
        int flow = 0;
        for(;;)
        {
            memset(a,0,sizeof(a));
            queue<int> que;
            que.push(s);
            a[s]=INF;
            while(!que.empty())
            {
                int x = que.front();
                que.pop();
                for(int i = 0;i<G[i].size();i++)
                {
                    Edge& e = edges[G[x][i]];
                    if(!a[e.to]&&e.cap>e.flow)//如果e.to节点还没有加过流(这一次BFS)
                    {
                        p[e.to] = G[x][i];
                        a[e.to] = min(a[x],e.cap-e.flow);
                        que.push(e.to);
                    }
                }
                if(a[t]) break;//若已拓展到t点,跳出
            }
            if(!a[t])//若无法到达a点,说明无增广路,结束算法
            for(int u = t;u!=s;u=edges[p[u]].from)//从t开始向前更新路径上的流
            {
                edges[p[u]].flow+=a[t];
                edges[p[u]^1].flow-=a[t];//亦或是相反边的编号
            }
            flow += a[t];
        }
        return flow;
    }
};

//Ford Fulkerson
#include <iostream>
#include <vector>
#include <memory.h>
#define maxn 1005
#define INF 0x3f3f3f3f
using namespace std;
struct edge
{
    int to;//终点
    int cap;//容量
    int rev;//反向边号
};
vector<edge> G[maxn];//图的邻接表表示
bool used[maxn];//DFS中用到的访问标记
void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});//记录反向边在to个节点的vector中的位置
    G[to].push_back((edge){from,0,G[from].size()-1});
}
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    used[v]=1;
    for(int i = 0;i<G[v].size();i++)
    {
        edge& e = G[v][i];
        if(!used[e.to]&&0<e.cap)
        {
            int d = dfs(e.to,t,min(e.cap,f));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;//未找到增广路
}
int max_flow(int s,int t)
{
    int flow = 0;
    for(;;)
    {
        memset(used,0,sizeof(used));
        int f = dfs(s,t,INF);
        if(f==0)
        {
            return flow;
        }
        flow += f;
    }
}

//Dinic
#include <iostream>
#include <vector>
#include <queue>
#include <memory.h>
#define maxn 1005
using namespace std;
struct edge
{
    int to;
    int cap;
    int rev;
};
vector<edge> G[maxn];//图的邻接表表示
int level[maxn];//顶点到原点的距离标号
int iter[maxn];//当前弧,在之前的变已经没有用了
void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
//通过BFS寻找从原点出发的且未满流的距离标号
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while(!que.empty())
    {
        int v = que.front();
        que.pop();
        for(int i = 0;i<G[v].size();i++)
        {
            edge& e = G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to] = level[v]+1;
                que.push(e.to);
            }
        }
    }
}
//通过dfs寻找增广路
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int& i = iter[v];i<G[v].size();i++)
    {//当前弧优化,iter[v]的值在随着i改变
        edge& e = G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d = dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;//找不到增广路
}

以上模板的表示方式都不太一样,理解后可方便自己选择

参考文章:

以上。

原文地址:https://www.cnblogs.com/zhanhonhao/p/11285031.html