【模板】网络最大流

来源:互联网 发布:数据库sql语句大全 编辑:程序博客网 时间:2024/05/22 00:21

学习网络流中。。。
目前的三个算法:

FF算法

大致步骤:
DFS不断寻找增广路径然后更新最大流

/********************************************Ford-Fulkerson 算法 这玩意比较慢,洛谷上的模板题只能够跑过9个点 ********************************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<algorithm>using namespace std;#define MAX 10100#define MAXL 210000#define rg register #define INF 1000000000inline int read(){       rg int x=0,t=1;rg char ch=getchar();       while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();       if(ch=='-'){t=-1;ch=getchar();}       while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}       return x*t;}int N,M,S,T,Ans=0;bool vis[MAX];struct Line{       int v,next,w,fb;}e[MAXL];int h[MAX],cnt=1;inline void Add(rg int u,rg int v,rg int w){        e[cnt]=(Line){v,h[u],w,cnt+1};        h[u]=cnt++;        e[cnt]=(Line){u,h[v],0,cnt-1};//存反边         h[v]=cnt++;}int DFS(rg int u,rg int t,rg int f)//从u到t,当前流量f {        if(u==t||f==0)return f;//到达终点或者已经无法增广了         vis[u]=true;//标记为访问过         for(int i=h[u];i;i=e[i].next)//访问所有边         {                rg int v=e[i].v,d;                if(!vis[v]&&e[i].w>0&&(d=DFS(v,t,min(e[i].w,f))))                //如果v未访问并且这条边的流量>0并且                 //当前寻找出来的可以更新的流量不为0                 {                       e[i].w-=d;//更新流量                        e[e[i].fb].w+=d;//反边                       return d; //返回当前的最大流量                 }        }        return 0;}int main(){        N=read();M=read();S=read();T=read();        for(rg int i=1;i<=M;++i)        {               rg int u=read(),v=read(),w=read();               Add(u,v,w);        }        rg int Ans=0;        while(1)//不断寻找增广路径         {               for(rg int i=1;i<=N;++i)vis[i]=false;               rg int f=DFS(S,T,INF);//找增广路径                if(!f)break;               Ans+=f;        }        printf("%d\n",Ans);        return 0;}

EK算法

大致步骤:
和FF算法的思想是一样的,但是使用BFS来寻找增广路径,效率比FF更高

/********************************************EK算法 比FF算法快多了,利用BFS寻找增广路可以解决Dinic解决不了的图(不能够分层的图) ********************************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<algorithm>using namespace std;#define MAX 10100#define MAXL 210000#define rg register #define INF 1000000000inline int read(){       rg int x=0,t=1;rg char ch=getchar();       while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();       if(ch=='-'){t=-1;ch=getchar();}       while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}       return x*t;}int N,M,S,T,Ans=0;int a[MAX];queue<int> Q; int pre[MAXL];struct Line{       int u,v,next,w,c,fb;//w是流量,c是容量  }e[MAXL];int h[MAX],cnt=1;inline void Add(rg int u,rg int v,rg int w){        e[cnt]=(Line){u,v,h[u],0,w,cnt+1};        h[u]=cnt++;        e[cnt]=(Line){v,u,h[v],0,0,cnt-1};//存反边         h[v]=cnt++;}int main(){        N=read();M=read();S=read();T=read();        for(rg int i=1;i<=M;++i)        {               rg int u=read(),v=read(),w=read();               Add(u,v,w);        }        rg int Ans=0;        while(1)//不断寻找增广路径         {               for(rg int i=1;i<=N;++i)a[i]=0;               while(!Q.empty())Q.pop();               Q.push(S);               pre[S]=0;               a[S]=INF;               while(!Q.empty())               {                     int u=Q.front();Q.pop();                     for(int i=h[u];i;i=e[i].next)                     {                           int v=e[i].v;                           if(!a[v]&&e[i].c>e[i].w)//可以增广                            {                                a[v]=min(a[u],e[i].c-e[i].w);//求最小的流量                                pre[v]=i;//储存增广路径                                 Q.push(v);                            }                     }                     if(a[T])break;//增广到了终点                }               if(!a[T])break;//未增广                for(int u=T;u!=S;u=e[pre[u]].u)//增加流量                {                      e[pre[u]].w+=a[T];                      e[e[pre[u]].fb].w-=a[T];               }               Ans+=a[T];        }        printf("%d\n",Ans);        return 0;}

Dinic

这是目前,我学的最优的一个最大流算法(我太弱了!!!)
大致步骤:
先用BFS对图进行分层
再用DFS寻找增广路径

Dinic是FF的升级版?(我是这么觉得的。。。)
效率高很多
但是有些图不能够分层。。。。所以。。。。。
学习一下EK还是比较重要的

/********************************Dinic算法对于可以分层的图而言效率比EK和FF高很多 ********************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<algorithm>using namespace std;#define MAX 10100#define MAXL 210000#define rg register #define INF 1000000000inline int read(){       rg int x=0,t=1;rg char ch=getchar();       while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();       if(ch=='-'){t=-1;ch=getchar();}       while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}       return x*t;}int N,M,S,T,Ans=0;bool vis[MAX];struct Line{       int v,next,w,fb;}e[MAXL];int h[MAX],cnt=1;int level[MAX];inline void Add(rg int u,rg int v,rg int w){        e[cnt]=(Line){v,h[u],w,cnt+1};        h[u]=cnt++;        e[cnt]=(Line){u,h[v],0,cnt-1};//存反边         h[v]=cnt++;}inline bool BFS()//分层 {        for(int i=1;i<=N;++i)level[i]=0;        level[S]=1;        queue<int> Q;        while(!Q.empty())Q.pop();        Q.push(S);        while(!Q.empty())        {               int u=Q.front();Q.pop();               for(int i=h[u];i;i=e[i].next)               {                        int v=e[i].v;                        if(e[i].w&&!level[v])//可以增广                         {                               level[v]=level[u]+1;                               Q.push(v);                        }               }        }        return level[T];//返回是否存在增广路 }int DFS(rg int u,rg int t,rg int f)//从u到t,当前流量f {        if(u==t||f==0)return f;//到达终点或者已经无法增广了         int re=0;//返回值         for(int i=h[u];i;i=e[i].next)//访问所有边         {                rg int v=e[i].v,d;                if(e[i].w&&level[v]==level[u]+1)//可以增广,并且满足分层图的要求                 {                       d=DFS(v,T,min(f,e[i].w));                       re+=d;                       f-=d;                        e[i].w-=d;//更新流量                        e[e[i].fb].w+=d;//反边                }        }        return re;}inline int Dinic(){        int re=0;        while(BFS())re+=DFS(S,T,INF);        return re;}int main(){        N=read();M=read();S=read();T=read();        for(rg int i=1;i<=M;++i)        {               rg int u=read(),v=read(),w=read();               Add(u,v,w);        }        rg int Ans=Dinic();        printf("%d\n",Ans);        return 0;}