[洛谷3376] 网络最大流模板题
题意
网络最大流模板题,题意很直白。
给出源点,汇点,点个数,边条数,以及每条边的流量,求源点到汇点的最大流量。
思路
Dinic算法简介
最大流经典算法Dinic算法,理论复杂度\(O(n^2m)\),但是实际运用中远远达不到这个上界,可以说是比较容易实现的效率最高的网络流算法之一,一般能处理\(10^4 -10^5\)规模的网络,特别的地,Dinic算法求解二分图最大匹配的理论时间复杂度为\(O(m\sqrt{n})\),实际表现则更快。
实现步骤
- 在残量网络(剩余流量大于0的子图)上BFS求出节点的层次,构造分层图
- 在分层图上DFS寻找增广路,在回溯时实时更新剩余流量,每个点可以流向多条边。
优化技巧
当前弧优化
一个点可能有多条出边,在DFS寻找增广路的时候,如果遍历该点的出边时,发现有些边已经没有剩余流量时,记录下当前遍历的点,下次再碰到该点时,无需从头开始遍历,直接从记录的位置开始遍历(因为记录位置之前的出边都没有剩余流量了,没有遍历的必要,代码实现:边使用链式前向星存储,使用额外数组cur[]复制head[]的值,实现cur代替head进行遍历,并及时更新cur的值,也就是修改头结点的指向)。
多路增广优化
爆点优化
当DFS遍历时发现一个点没有了流出的流量,则把该点的deep值置为-2,将无用的点抛弃,下次无需再遍历。
代码实现
#include<cstdio> #include<cstring> #include<queue> using namespace std; #define sf(x) scanf("%d",&(x)) const int MAXN=1e4+5; const int MAXM=1e5+5; const int INF=1e8+10; int N,M,S,T; struct node{int v,flow,next;}edge[MAXM*2]; int head[MAXN],cur[MAXN],num=0;//注意这里必须从0开始 inline void add(int x,int y,int z) { edge[num].v=y;edge[num].flow=z; edge[num].next=head[x];head[x]=num++; } queue<int> q; int deep[MAXN]; bool BFS() { memset(deep,0,sizeof(deep)); deep[S]=1; q.push(S); while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) if(!deep[edge[i].v]&&edge[i].flow) { deep[edge[i].v]=deep[u]+1; q.push(edge[i].v); } } return deep[T]; } int DFS(int now,int nowflow) { if(now==T) return nowflow; int totflow=0;//从这个点总共可以增广多少流量 for(int i=cur[now];i!=-1;i=edge[i].next) { cur[now]=i;//当前弧优化,记录压榨到哪条边 if(deep[edge[i].v]==deep[now]+1&&edge[i].flow)//只有满足距离要求与流量要求的点才能进行增广 { int canflow=DFS(edge[i].v,min(nowflow,edge[i].flow)); if(!canflow)continue;//当可增广的流量大于0,更新 edge[i].flow-=canflow;edge[i^1].flow+=canflow;//增广 totflow+=canflow; nowflow-=canflow; if(nowflow<=0) break; //当前点已经没有流量 快100ms } } if(!totflow)deep[now]=-2;//爆点优化,该点已经没有剩余流量,证明不必要的点下一次不需要遍历 return totflow; } void Dinic() { int ans=0; while(BFS())//每次构造分层图 { memcpy(cur,head,sizeof(head)); //当前弧优化 ans+=DFS(S,INF);//进行增广 } printf("%d",ans); } int main() { sf(N);sf(M);sf(S);sf(T); memset(head,-1,sizeof(head)); for(int i=1;i<=M;i++) { int x,y,z; sf(x);sf(y);sf(z); add(x,y,z),add(y,x,0); } Dinic(); return 0; }
参考博文:
https://www.cnblogs.com/zwfymqz/p/8280746.html#_label4
https://www.bilibili.com/video/av21945401?from=search&seid=17416394282430843291
https://www.cnblogs.com/SYCstudio/p/7260613.html
来源:https://www.cnblogs.com/sstealer/p/12207600.html