zoukankan      html  css  js  c++  java
  • 网络流 之 dinic 算法

    网络流指的是:网络流(network-flows)是一种类比水流的解决问题方法。(类似于水管群,有一个源点(水无限多),和一个汇点,最大流就代表这个点水管群(边集)每秒最大能送道汇点的水量)

    这个怎么求,首先是枚举从原点能到汇点的路径,然后找到这个路径边权的最小值,这个路劲的每条边减去这个值,大概这个样子

    (借用同校某大佬的图)

    但是明显没给我反悔的机会嘛,万一我不想这样做,岂不没地方反悔了

    ~Point 1 反边~

    这东西就是类似于给你一个反悔的机会的,因为反向图建过去的丑的一批的路径等价于每个单独路径

    原理:正向边减去当前流量,反向边加上当前流量。

    比如这张图中,有一个产地,要运货给销地(也就是6号点),问如何才能给销地运输最多货物(图片是学校ppt的)

    显然这张图就没有刚才那张好办,因此我们加入反边这一个概念

    问什么加入反边呢,先给你看这会在哪个加了反边的图(蓝色为反边边权)

    (该运输方案表示:2吨产品沿有向路P1(1,2,4,6)运到销地;1吨产品沿有向路P2(1,2,5,6)运到销地;2吨产品沿有向路P3(1,3,5,6)运到销地。)

     现在我们又找到一条P4(1,2,3,4,6)的路径。

    Level 1.P3376 【模板】网络最大流

    就是一个裸题……

    由于这个代码是第一次掌握,有些东西还不能完全化为自己的理解,故有些地方传承了教练给的代码的格式,这些东西我会在里面说明的

    但是作为入门内容,还是打一下。我的注释应该会给的很清楚吧

    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<stack>
    #include<vector>
    #include<map>
    #include<string>
    #include<algorithm>
    
    using namespace std;
    
    int n,m,st,ed,size,ans,ct[10086],head[10086],dep[10086],vis[10086];
    
    struct edge{
        int next,to,dis,start;
    }e[200860];
    
    void addedge(int next,int to,int dis)
    {
        e[size].to=to;  
        e[size].dis=dis; 
        e[size].next=head[next];
        e[size].start=next;  //这个貌似没什么用 
        head[next]=size;
        size++;  //还有另一种写法,详见下面addedge 
    }
    
    void addedge(int next,int to,int dis)
    {
        e[++size].dis=dis;  //这种写法可以先令size=1,这样 边就从2开始存了,也能满足异或1是反向边 
        e[size].to=to;   //或者令size =-1 和就和上面写法差不多 
        e[size].next=head[next];
        head[next]=size;
     } 
    
    int bfs()
    {
        queue <int> q;
        memset(dep,0,sizeof(dep));
        memset(vis,0,sizeof(vis));
        q.push(st);
        vis[st]=1;
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            int i,j,k;
            for(i=head[t];i!=-1;i=e[i].next)
            {
                j=e[i].to;
                k=e[i].dis;
                if(k>0&&!dep[j]&&!vis[j])  //dep类似于图的深度,把网络流看作水流,防止回流 
                {
                    dep[j]=dep[t]+1;
                    q.push(j);
                    vis[j]=1;
                }
            }
        }
        return vis[ed];  //如果终点还能被增广就就返回1 
    }
    
    int dfs(int t,int nowwater)
    {
        if(t==ed||!nowwater) return nowwater;  //1.到终点返回答案,2.走不通返回0 
        int tot=0;
        for(int &i=ct[t];i!=-1;i=e[i].next)  //当前弧优化,防止无用寻找 
        {
            int j=e[i].to;
            int &k=e[i].dis;  //暂时不知道这个&有什么意思,但是去掉也可以过 
            if(k>0&&dep[j]==dep[t]+1)
            {
                int f=dfs(j,min(k,nowwater-tot));
                e[i].dis-=f;
                e[i^1].dis+=f;  //异或1让二进制最后一位变化 比如1001001 ^1 ==1001000 刚好指向另一条边 
                tot+=f;
                if(nowwater==tot) return tot;
            }
        }
        return tot; //当前能流到终点的最大水量 
    }
    
    void dinic()
    {
        while(bfs())
        {
            for(int i=1;i<=n;i++)
            {
                ct[i]=head[i];
            }
            ans+=dfs(st,0x3f3f3f3f);  //初始值一定设为最大值 
        }
    }
    
    int main()
    {
        int i,j;
        scanf("%d %d %d %d",&n,&m,&st,&ed);
        memset(head,-1,sizeof(head));
        for(i=1;i<=m;i++)
        {
            int t1,t2,t3;
            scanf("%d %d %d",&t1,&t2,&t3);  //建边建正向边和反向边 
            addedge(t1,t2,t3);
            addedge(t2,t1,0);
        }
        dinic();
        printf("%d",ans);
        return 0;
    }

     时间复杂度O(可以过)

  • 相关阅读:
    [Next] 六.next的优化
    [Next] 五.next自定义内容
    Mac解决端口占用
    [Next] 四.在next中引入redux
    [Next] 服务端渲染知识补充
    [Next] 三.next自定义服务器和路由
    哪些使用UDP、TCP、IP协议
    IDEA配置git
    ssm整合配置
    git传输远程仓库
  • 原文地址:https://www.cnblogs.com/zsx6/p/11143261.html
Copyright © 2011-2022 走看看