zoukankan      html  css  js  c++  java
  • 网络流初步

    其实网络流很久之前已经学过,但是因为一些原因搁置了很久,于是想再系统地复习一下.

    由于博主能力有限,所以关于网络流知识也是了解个大概,这里只是简单介绍,并且说一下博主的感性理解


    最大流

      EK増广路算法

        很容易理解的一个算法,也就是我们不断地bfs找出一条増广路然后更新剩余容量,直到更新完毕,类似于SPFA做法.时间复杂度$O(nm^{2})$;

        这里不再附上代码,因为后面的费用流就要用EK+SPFA,而只是求最大流,推荐Dinic.

      Dinic算法

        与EK不同的是,Dinic算法增加了一些优化,这里引进了深度这个概念,通过在同一深度图中増广,一个点可以向多个点进行多流増广,并有减枝;

        于是Dinic就可以达到$O(n^{2}m)$的优秀时间复杂度,可以代替匈牙利算法跑二分图匹配,时间复杂度$O(nsqrt{n})$;

        PS:关于二分图匹配时间复杂度可以这么想,由于一个点多流推进,同时増广多个点,而且深度小,所以时间复杂度就十分优秀;

        Code:

        

    #include<bits/stdc++.h>
    #define maxn 10008
    using namespace std;
    int n,m,head[maxn],s,t,cent=1,d[maxn],maxflow;
    int min(int a,int b){return a<b?a:b;}
    const int inf=1<<30;
    struct node{
        int next,to,w;
    }edge[maxn<<5];
    queue<int >q;
    
    void add(int u,int v,int w){
        edge[++cent]=(node){head[u],v,w};head[u]=cent;
        edge[++cent]=(node){head[v],u,0};head[v]=cent;
    }
    
    bool bfs(){
        memset(d,0,sizeof d);
        while(q.size()) q.pop();
        q.push(s),d[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=edge[i].next){
                int y=edge[i].to;
                if(edge[i].w&&!d[y]){
                    q.push(y);d[y]=d[x]+1;
                    if(y==t) return 1;
                }
            }
        }
        return 0;
    }
    
    int Dinic(int x,int flow){
        if(x==t) return flow;
        int rest=flow,k,y;
        for(int i=head[x];i;i=edge[i].next){
            if(edge[i].w&&d[y=edge[i].to]==d[x]+1){
                k=Dinic(y,min(rest,edge[i].w));
                edge[i].w-=k;
                edge[i^1].w+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    
    int main(){
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,a,b,w;i<=m;i++){
            scanf("%d%d%d",&a,&b,&w);
            add(a,b,w);
        }
        int flow=0;
        while(bfs())
            while(flow=Dinic(s,inf)) maxflow+=flow;
        printf("%d",maxflow);
    }

    费用流

      费用流应该是我们见得最多的,而费用流跑二分图最大带权匹配极其优秀,费用流采用EK算法,不过每一次要跑一次SPFA,时间复杂度上升,如果要卡图了话,可能会崩;

      但是由于图一般比较小,而且Dijkstra处理负权值问题有些复杂(要牵扯到势的辅助),所以还是普遍用SPFA求费用流;

      Code

      

    #include<bits/stdc++.h>
    #define maxn 50007
    #define N 5007
    #define inf 2139062143
    using namespace std;
    int n,m,s,t,incf[N],head[N],cent=1,dis[N];
    int vis[N],maxflow,mincost,pre[N];
    struct node{
        int next,to,w,cost;
    }edge[maxn<<3];
    
    inline void add(int u,int v,int w,int c){
        edge[++cent]=(node){head[u],v,w,c};head[u]=cent;
        edge[++cent]=(node){head[v],u,0,-c};head[v]=cent;
    }
    
    bool spfa(){
        queue<int >q;
        memset(pre,0,sizeof(pre)); 
        memset(dis,127,sizeof dis);
        memset(vis,0,sizeof vis);
        q.push(s);dis[s]=0;vis[s]=1;
        incf[s]=1<<30;
        while(!q.empty()){
            int x=q.front();q.pop();
            vis[x]=0;
            for(int i=head[x],y;i;i=edge[i].next){
                if(!edge[i].w) continue;
                if(dis[y=edge[i].to]>dis[x]+edge[i].cost){
                    dis[y]=dis[x]+edge[i].cost;
                    incf[y]=min(incf[x],edge[i].w);
                    pre[y]=i;
                    if(!vis[y]) q.push(y),vis[y]=1;
                }
            }
        }
        if(dis[t]==2139062143) return 0;
        return 1;
    }
    
    void update(){
        int x=t;
        while(x!=s){
            int i=pre[x];
            edge[i].w-=incf[t];
            edge[i^1].w+=incf[t];
            x=edge[i^1].to;
        }
        maxflow+=incf[t];
        mincost+=dis[t]*incf[t];
    //    cerr<<mincost<<endl;
    }
    
    int main(){
    //    freopen("cin.in","r",stdin);
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,a,b,c,d;i<=m;i++){
            scanf("%d%d%d%d",&a,&b,&c,&d);
            add(a,b,c,d);
        }
        while(spfa()) update();
        printf("%d %d",maxflow,mincost);
    }
  • 相关阅读:
    Linux(CentOS)下squid代理服务器配置-五岳之巅
    用类实现二叉树
    django--02 模板的使用
    django --01 helloworld样例入门
    微指数爬虫
    celery_01 _celery安装启动
    python多线程几种方法实现
    crontab问题处理
    python可视化--matplotlib
    python网页爬虫--京东家电版块
  • 原文地址:https://www.cnblogs.com/waterflower/p/11369337.html
Copyright © 2011-2022 走看看