当前位置: 首页 > news >正文

网络流基础

前言:

关于网络流,按董大佬的话,就是个板子,会打也没用

正文:

最大流

最大流的基础求法就是増广路算法($EK$)

虽然它跑的慢,但也要会打,因为可以魔改求费用流

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

using std::queue;
const int maxn=11111;
#define inf (0x3f3f3f3f)

class Max_Flow
{
    private:
        
        struct edge
        {
            int to,next,cap;
            edge(){}
            edge(int to,int next,int cap):to(to),next(next),cap(cap){}
        };
        
        edge e[maxn*20];
        int cnt,head[maxn];

        void add(int from,int to,int cap)
        {
            e[++cnt]=edge(to,head[from],cap);
            head[from]=cnt;
        }

        struct node
        {
            int pre,kth;
        };
        
        node p[maxn];
        bool vis[maxn];
    
        bool bfs(int s,int t)
        {
            memset(p,0,sizeof(p));
            memset(vis,0,sizeof(vis));
            queue<int>q;
            q.push(s);
            p[s].pre=s;
            vis[s]=1;
            while(!q.empty())
            {
                int u=q.front(); q.pop();
                for(int i=head[u];i!=-1;i=e[i].next)
                {
                    int v=e[i].to;
                    if(!vis[v]&&e[i].cap)
                    {
                        vis[v]=1;
                        p[v].pre=u;
                        p[v].kth=i;
                        if(v==t) return 1;
                        q.push(v);
                    }
                }
            } 
            return 0;
        }
        
    public:

        Max_Flow()
        {
            cnt=-1;
            memset(head,-1,sizeof(head));
        }
        
        void addedge(int u,int v,int w)
        {
            add(u,v,w);
            add(v,u,0);
        }
        
        int EK(int s,int t)
        {
            int maxflow=0;
            while(bfs(s,t))
            {
                int minn=inf;
                for(int i=t;i!=s;i=p[i].pre)
                    minn=std::min(minn,e[p[i].kth].cap);
                for(int i=t;i!=s;i=p[i].pre)
                {
                    e[p[i].kth].cap-=minn;
                    e[p[i].kth^1].cap+=minn;
                }
                maxflow+=minn;
            }
            return maxflow; 
        }
}flow;

int main()
{
    int n,m,s,t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1,u,v,w;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        flow.addedge(u,v,w);
    }
    printf("%d\n",flow.EK(s,t));
    return 0;
}

当然 $EK$ 的效率显然无法满足我们的要求

所以我们要进行优化,先将图进行分层,再去増广

于是我们有了 $Dinic$ 算法,还有基于它的各种鬼畜优化

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

using std::queue;
const int maxn=11111;
#define inf (0x3f3f3f3f)

class Max_Flow
{

    private:

        struct edge
        {
            int to,next,cap;
            edge(){}
            edge(int to,int next,int cap):to(to),next(next),cap(cap){}
        };

        edge e[maxn*20];
        int cnt,head[maxn];

        void add(int from,int to,int cap)
        {
            e[++cnt]=edge(to,head[from],cap);
            head[from]=cnt;
        }

        int deep[maxn];

        bool bfs(int s,int t)
        {
            memset(deep,0,sizeof(deep));
            queue<int>q;
            q.push(s);
            deep[s]=1;
            while(!q.empty())
            {
                int u=q.front(); q.pop();
                for(int i=head[u];i!=-1;i=e[i].next)
                {
                    int v=e[i].to;
                    if(!deep[v]&&e[i].cap)
                    {
                        deep[v]=deep[u]+1;
                        if(v==t) return 1;
                        q.push(v);
                    }
                }
            }
            return 0;
        }

        int dfs(int u,int limit,int t)
        {
            if(u==t||!limit) return limit;
            int sum=0;
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].to;//关于当前弧优化,我并不会
                if(deep[v]==deep[u]+1&&e[i].cap)
                {
                    int flow=dfs(v,std::min(limit-sum,e[i].cap),t);
                    if(!flow) deep[v]=0;//据说叫炸点优化,感觉好霸气的样子
                    sum+=flow;
                    e[i].cap-=flow;
                    e[i^1].cap+=flow;
                    if(sum==limit) break;//这句剪枝一定要加上,否则会慢很多
                }
            }
            return sum;
        }

    public:

        Max_Flow()
        {
            cnt=-1;
            memset(head,-1,sizeof(head));
        }

        void addedge(int u,int v,int c)
        {
            add(u,v,c);
            add(v,u,0);
        }

        int Dinic(int s,int t)
        {
            int maxflow=0;
            while(bfs(s,t))
            {
                maxflow+=dfs(s,inf,t);
            }
            return maxflow;
        }

}flow;

int main()
{
    int n,m,s,t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1,u,v,c;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&c);
        flow.addedge(u,v,c);
    }
    printf("%d\n",flow.Dinic(s,t));
    return 0;
}

费用流

关于费用流,就是将 $EK$ 的 $bfs$ 魔改为 $spfa$ ,每次増广出一条最短路

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

using std::queue;
const int maxn=5555;
#define inf (0x3f3f3f3f)

class Mincost_Maxflow
{
    
    private:
        
        struct edge
        {
            int to,next,cap,dis;
            edge(){}
            edge(int to,int next,int cap,int dis):to(to),next(next),cap(cap),dis(dis){}
        };
        
        edge e[maxn*20];
        int cnt,head[maxn];
        
        void add(int from,int to,int cap,int dis)
        {
            e[++cnt]=edge(to,head[from],cap,dis);
            head[from]=cnt;
        }
        
        struct node
        {
            int pre,kth;
        };
        
        node p[maxn];
        int dis[maxn];
        bool vis[maxn];
        
        bool spfa(int s,int t)
        {
            memset(p,0,sizeof(p));
            memset(vis,0,sizeof(vis));
            memset(dis,inf,sizeof(dis));
            queue<int>q;
            q.push(s);
            p[s].pre=s;
            dis[s]=0,vis[s]=1;
            while(!q.empty())
            {
                int u=q.front(); q.pop(); vis[u]=0;
                for(int i=head[u];i!=-1;i=e[i].next)
                {
                    int v=e[i].to;
                    if(dis[v]>dis[u]+e[i].dis&&e[i].cap)
                    {
                        dis[v]=dis[u]+e[i].dis;
                        p[v].pre=u;
                        p[v].kth=i;
                        if(!vis[v])
                        {
                            q.push(v);
                            vis[v]=1;
                        }
                    }
                }
            }
            return p[t].pre;
        }
    
    public:
        
        int mincost,maxflow;
        
        Mincost_Maxflow()
        {
            cnt=-1;
            memset(head,-1,sizeof(head));
        }
        
        void addedge(int u,int v,int c,int w)
        {
            add(u,v,c,w);
            add(v,u,0,-w);
        }
        
        void mincost_maxflow(int s,int t)
        {
            while(spfa(s,t))
            {
                int minn=inf;
                for(int i=t;i!=s;i=p[i].pre)
                    minn=std::min(minn,e[p[i].kth].cap);
                for(int i=t;i!=s;i=p[i].pre)
                {
                    e[p[i].kth].cap-=minn;
                    e[p[i].kth^1].cap+=minn;
                }
                maxflow+=minn;
                mincost+=minn*dis[t];
            }
        }
        
}flow;

int main()
{
    int n,m,s,t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1,u,v,c,w;i<=m;i++)
    {
        scanf("%d%d%d%d",&u,&v,&c,&w);
        flow.addedge(u,v,c,w);
    }
    flow.mincost_maxflow(s,t);
    printf("%d %d\n",flow.maxflow,flow.mincost);
    return 0;
}

后序:

关于最大流的 $ISAP$ 算法和 $HLPP$ 预流推进以及 $zkw$ 费用流

因为我太菜了,所以都没学,想学的话可以私聊这位大佬 

转载于:https://www.cnblogs.com/Vscoder/p/10530242.html

相关文章:

  • 不要自建Kubernetes
  • 容器镜像
  • C++智能指针与类模板
  • React 优秀插件记录
  • chrome浏览器的两个坑,以及其他
  • Visual Studio Community 2017 配置 OpenGL 环境 (NuGet)
  • 华为传输千兆5G光端机 PTN960
  • 持续集成-DevOps概念篇
  • Vue(1)之—— Vuex学习笔记
  • 内购掉单问题处理
  • 闲话队列
  • Linux 查看IP
  • Exchange Server无法通过脚本启用邮箱并关闭EAS功能
  • 行内元素和块级元素
  • ZFS的元数据
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 03Go 类型总结
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • JavaScript函数式编程(一)
  • JS实现简单的MVC模式开发小游戏
  • Less 日常用法
  • MobX
  • ReactNative开发常用的三方模块
  • Solarized Scheme
  • spring-boot List转Page
  • 机器学习中为什么要做归一化normalization
  • 基于组件的设计工作流与界面抽象
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 走向全栈之MongoDB的使用
  • 最简单的无缝轮播
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • #include<初见C语言之指针(5)>
  • #Z0458. 树的中心2
  • ${factoryList }后面有空格不影响
  • ( 10 )MySQL中的外键
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • ******之网络***——物理***
  • .NET Core引入性能分析引导优化
  • .net 后台导出excel ,word
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .net2005怎么读string形的xml,不是xml文件。
  • .Net下的签名与混淆
  • @Async注解的坑,小心
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • []error LNK2001: unresolved external symbol _m