网络流最大流入门(Dinic算法)模板
Posted mm-puppy-lyt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流最大流入门(Dinic算法)模板相关的知识,希望对你有一定的参考价值。
前言
本来先搞计算几何再搞网络流的,但是**总是发网络流的题,然后天天被信息组巨佬爆踩,所以先学一下最基本的Dinic算法吧。我也只是大致理解了流程,其实不懂也没事,只要会堆代码就好了(QAQ),所以下面只有教你如何堆代码啦(……)。
基本概念
图和收发点
一个图是由点集V={vi}和V中元素的无序对的一个集合E={ek}所构成的二元组,记为G=(V,E),V中的元素vi叫做顶点,E中的元素ek,叫做边。
仅有一个入次为0的点vs称为发点(源),一个出次为0的点vt称为收点(汇),其余点为中间点,这样的网络G称为容量网络,常记做G=(V,E,C)。
容量和流量
设有向连通图G=(V,E),G的每条边(vi,vj)上的非负数cij称为边的容量。对任一G中的边(vi,vj)有流量fij,称集合f={fij}为网络G上的一个流。右图即为一个有向连通图,括号中第一个数字代表容量,第二个数字代表流量。
可行流
称满足下列两个条件的流为可行流:
1.容量限制条件:对G中的每条边(vi,vj),有0≤fij≤cij;即每条边上的流量非负而且最大也只能达到容量的限制。
2.平衡条件:对中间点vi,有
,即物资的输入量和输出量相等。
对发、收点vs,vt,,有
,fij为网络流的总流量。
一个流f={fij},当fij=cij,则称流f对边(vi,vj)是饱和的,否则称f对(vi,vj)不饱和。
用途
当然就是求有向图中指定的某点到另一点的最大可行流(自己归纳的),解决这一问题的最好的算法就是Dinic了,下面给出具体流程。
算法流程
用n表示点数,m表示边数,st表示要求的起点,ed表示要求的终点(不专业术语,不要模仿呐)
首先存边
int head[],tot; struct edge{int v,w,nxt;}e[]; void addn(int u,int v,int w){ e[++tot]=(edge){v,w,head[u]}; head[u]=tot; } //存边:u->v(w)和v->u(0) addn(u,v,w); addn(v,u,0);
然后码出每次dfs前需要的bfs建图
用cur[ ]代替变化的head[ ],dis[ ]表示到每个点到st的距离(每隔一条边距离就是1)
int bfs(int st,int ed) { //bfs建图 queue<int>que; memset(dis,-1,sizeof(dis)); dis[st]=0; que.push(st); while(!que.empty()) { int x=que.front(); que.pop(); for(int i=head[x];i;i=e[i].nxt) { int now=e[i].v; if(dis[now]==-1&&e[i].w) { que.push(now); dis[now]=dis[x]+1; } } } return dis[ed]!=-1; }
接着码dfs查询
int dfs(int x,int t,int maxflow) { if(x==t) return maxflow; int ans=0; for(int i=cur[x];i;i=e[i].nxt) { int now=e[i].v; if(dis[now]!=dis[x]+1||!e[i].w||ans>=maxflow) continue; cur[x]=i; int f=dfs(now,t,min(e[i].w,maxflow-ans)); e[i].w-=f; if(i&1) e[i+1].w+=f; else e[i-1].w+=f; ans+=f; } if(!ans) dis[x]=-1; return ans; }
然后大致流程就出来了,不断重复:bfs建图,dfs查询改值,直到不能再进行
现在放出全部代码
//dinic板子 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define INF 0x3f3f3f3f using namespace std; const int N=10000,M=100000; int n,m,tot,ss,dd,head[N+3]; struct edge{int v,w,nxt;}e[M*2+3]; int dis[N+3],cur[N+3]; void addn(int u,int v,int w){e[++tot]=(edge){v,w,head[u]};head[u]=tot;} int bfs(int st,int ed) { //bfs建图 queue<int>que; memset(dis,-1,sizeof(dis)); dis[st]=0; que.push(st); while(!que.empty()) { int x=que.front(); que.pop(); for(int i=head[x];i;i=e[i].nxt) { int now=e[i].v; if(dis[now]==-1&&e[i].w) { que.push(now); dis[now]=dis[x]+1; } } } return dis[ed]!=-1; } int dfs(int x,int t,int maxflow) { if(x==t) return maxflow; int ans=0; for(int i=cur[x];i;i=e[i].nxt) { int now=e[i].v; if(dis[now]!=dis[x]+1||!e[i].w||ans>=maxflow) continue; cur[x]=i; int f=dfs(now,t,min(e[i].w,maxflow-ans)); e[i].w-=f; if(i&1) e[i+1].w+=f; else e[i-1].w+=f; ans+=f; } if(!ans) dis[x]=-1; return ans; } int Dinic(int st,int ed) { int ans=0; while(bfs(st,ed)) { memcpy(cur,head,sizeof(head)); int k; // ans+=dfs(st,ed,INF); while(k=dfs(st,ed,INF)) ans+=k; } return ans; } int main() { scanf("%d %d %d %d",&n,&m,&ss,&dd); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d %d %d",&u,&v,&w); addn(u,v,w); addn(v,u,0); } cout<<Dinic(ss,dd); return 0; }
注意:题目不同,m和n的大小也不同,记得要更改呀~
完结~~第一篇学术文章;撒花撒花??ヽ(°▽°)ノ?
以上是关于网络流最大流入门(Dinic算法)模板的主要内容,如果未能解决你的问题,请参考以下文章