最大流算法学习

前几天学了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;
}

 

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

 

posted @ 2018-09-22 14:22  zxza695  阅读(181)  评论(0编辑  收藏  举报

Contact with me