• 初学网络流


    初学网络流

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

    引入:

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

    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;//找不到增广路
    }
    

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

    参考文章:

    以上。

  • 相关阅读:
    一万字详解 Redis Cluster Gossip 协议
    Java使用多线程异步执行批量更新操作
    闲鱼是如何实践一套完整的埋点自动化验证方案的?
    OSS 阿里云存储操作实例以及错误案例
    OSS 阿里云存储操作实例以及错误案例
    Java知识体系总结(2021版)
    倪文迪陪你学蓝桥杯2021寒假每日一题:1.11日(2017省赛A第9题)
    七分之一在线评论都有假,人工智能救一把?
    太委屈!曾一举击败英伟达,却因坚持研发背负骂名的国际 IT 大佬
    SpringBoot四大核心之自动装配——源码解析
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11285031.html
Copyright © 2020-2023  润新知