zoukankan      html  css  js  c++  java
  • 最大流算法学习

    前几天学了Dinic求最大流,来总结一下。

    网络流的概念是很多的。

    预备知识:

    在一个有向图上选择一个源点,一个汇点,每一条边上都有一个流量上限(以下称为容量),即经过这条边的流量不能超过这个上界,同时,除源点和汇点外,所有点的入流和出流都相等,而源点只有流出的流,汇点只有汇入的流。这样的图叫做网络流

    我们定义:
    源点:只有流出去的点
    汇点:只有流进来的点
    流量:一条边上流过的流量
    容量:一条边上可供流过的最大流量
    残量:一条边上的容量-流量

    算法思想:

    网络流的所有算法都是基于一种增广路的思想,下面首先简要的说一下增广路思想,其基本步骤如下:

    1.找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0(注意是小于而不是小于等于,这意味着这条边还可以分配流量),这条路径便称为增广路
    2.找到这条路径上最小的F[u][v](我们设F[u][v]表示u->v这条边上的残量即剩余流量),下面记为flow
    3.将这条路径上的每一条有向边u->v的残量减去flow,同时对于起反向边v->u的残量加上flow(为什么呢?我们下面再讲)
    4.重复上述过程,直到找不出增广路,此时我们就找到了最大流

    介绍下这个博客,写的十分简洁易懂。本博客内容部分转载自

    http://www.cnblogs.com/SYCstudio/p/7260613.html

    最小割:通俗一点理解就是最小的费用让A,B两个集合不连通.

    最大流最小割定理:最大流=最小割

    Dinic基本思想:

    1.不断找增广路,即从s-->t的可行路径,用dfs实现。

    2.运用了分层图优化,用bfs实现。

    3.可以用当前弧优化,即记录每个点已经访问过的边,下次dfs直接从没有访问过的边开始。

    例题:网络流24题

    推荐题:

    最大流模板

    飞行员配对方案问题

    [USACO4.2]草地排水Drainage Ditches

    方格取数问题//这道题前几天考了...

    最大流模板代码:

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=10000+5;
    const int M=200000+10;
    const int INF=0x3f3f3f3f;
    int n,m,s,t,num=1,head[N],dep[N],ans,q[N*3],cur[N];
    struct E{
        int next,to,dis;
    }e[M];
     void add( int u, int v, int w){
        e[++num].to=v;
        e[num].next=head[u];
        e[num].dis=w;
        head[u]=num;
    }
     int dfs( int u, int flow){
        if(u==t)return flow;
        for( int i=cur[u];i;i=e[i].next){//当前弧优化
             int v=e[i].to;
            if(dep[v]==dep[u]+1&&e[i].dis){
                 int w=dfs(v,min(flow,e[i].dis));
                if(w>0){
                    e[i].dis-=w;
                    e[i^1].dis+=w;
                    return w;
                }
            }
        }
        return 0;
    }
    inline int bfs(){
        memset(dep,0,sizeof(dep));
        int u,v;
        dep[s]=1;
        queue<int>q;
        q.push(s);
        while(!q.empty()){
            u=q.front();
            q.pop();
            for( int i=head[u];i;i=e[i].next){
                v=e[i].to;
                if(e[i].dis&&!dep[v]){
                    dep[v]=dep[u]+1;
                    if(v==t)return 1;
                    q.push(v);
                }
            }
        }
        return 0;
    }
     void Dinic(){
        while(bfs()){
        for( int i=1;i<=n;i++)
        cur[i]=head[i];//当前弧优化
        ans+=dfs(s,INF);
        }
    }
    int main(){
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for( int i=1;i<=m;i++){
             int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,0);
        }
        Dinic();
        printf("%d",ans);
        return 0;
    }

    总结:网络流的最大难度在于建图,这点十分关键,主要是理清楚题意,寻找条件。

  • 相关阅读:
    前端CSS部分知识整理
    css随笔记(持续更新)
    前端样式脚本本地化开发
    样式脚本本地化开发方法①【前端开发技巧】
    微信公众号吸粉简易新策略(自整理持续待更新)
    Wave
    无聊时百度了一下自己的名字。吓到我了
    Java实现 LeetCode 819 最常见的单词(暴力)
    Java实现 LeetCode 819 最常见的单词(暴力)
    Java实现 LeetCode 823 带因子的二叉树(DP)
  • 原文地址:https://www.cnblogs.com/sky-zxz/p/9690050.html
Copyright © 2011-2022 走看看