zoukankan      html  css  js  c++  java
  • 图论--网络流初步(最大流,增广路)

    以下内容为提高+难度。
    首先,以一个问题来引入算法:

    最大流问题,该问题描述如下:
    管道网络中每条边的最大通过能力(容量)是有限的,实际流量不超过容量。
    最大流问题(maximum flow problem),一种组合最优化问题,就是要讨论如何充分利用装置的能力,使得运输的流量最大,以取得最好的效果。

    关于最大流问题还有许多定义,具体参见紫书(算法竞赛入门经典)的P366,有详细说明(或者戳这里)。


    对于这个问题,有一个十分经典的算法:增广路算法。
    这个算法每次找到一条路径,记这条路径上的残量最小值为f(f>=1),则将这条路径上的边的残量都减小f,并将总流量flow也增加f。如此重复,直到没有增广路为止,此时的flow便是最大流。
    然后,解决这个问题,比较有效的方法–最短增广路算法,即每次沿着最短的一条增广路进行增广。
    有一种比较优秀的这种算法,Dinic算法。
    我对这个算法还没有清晰的认识,所以我只是贴一下代码(洛谷 P2936 [USACO09JAN]全流Total Flow
    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10001;
    inline int toint(char ch){
        if(ch>='A'&&ch<='Z'){
            return ch-'A'+1;
        }
        else{
            return ch-'a'+27;
        }
    }
    struct edge{
        int from,to,cap,flow;
    };
    int n,m,s=1,t=toint('Z');
    vector<edge> edges;
    vector<int> G[maxn];
    inline void addedge(int from,int to,int cap){
        edges.push_back((edge){from,to,cap,0});
        edges.push_back((edge){to,from,0,0});
        int m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    bool bfs(){
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(s);
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=0;i<G[x].size();i++){
                edge& e=edges[G[x][i]];
                if(!vis[e.to]&&e.flow<e.cap){
                    vis[e.to]=1;
                    q.push(e.to);
                    d[e.to]=d[x]+1;
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a){
        if(x==t||a==0){
            return a;
        }
        int flow=0,f;
        for(int& i=cur[x];i<G[x].size();i++){
            edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int Maxflow(){
        int flow=0;
        while(bfs()){
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,0x3f3f3f3f);
        }
        return flow;
    }
    int main(){
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            char ch1,ch2;
            int x,y,l;
            cin>>ch1>>ch2>>l;
            x=toint(ch1);
            y=toint(ch2);
            addedge(x,y,l);
        }
        printf("%d",Maxflow());
        return 0;
    }

    这里再给一道模板题:洛谷 P3376 【模板】网络最大流
    end

  • 相关阅读:
    常用linux命令及其设置
    shell脚本编写步骤及其常用命令和符号
    浏览器访问php脚本通过sendmail用mail函数发送邮件
    windows server 定期备份数据库脚本
    图片垂直水平居中
    "!function",自执行函数表达式
    jQuery(function(){})与(function(){})(jQuery) 的区别
    在Windows Server 2019通过Docker Compose部署Asp.Net Core
    Redis集群同步问题
    webapi跨域使用session
  • 原文地址:https://www.cnblogs.com/stone41123/p/7581287.html
Copyright © 2011-2022 走看看