Dinic算法

hkr04

2020-02-09 18:07:49

Personal

时间复杂度:$O(n^2m)$,实际运用远达不到这个上界,一般能处理$10^4$~$10^5$规模的网络。 怎么实现呢? 1. 在残量网络上使用BFS构造分层图 2. 在分层图上使用DFS尝试寻找增广路,并且实时更新每条边的容量 3. 重复执行1.2直到分层图中s不能到达t(没有增广路)为止 在优化$\text{BFS}$次数之后,我们还可以进行优化——**当前弧优化**。 对于在不同的分层图进行$\text{DFS}$的过程中,不重复走之前走过的**满流**的边,因为再走下去终究会卡住,是白做工。可以用一个数组$\text{cur}$记录一下当前点更新到哪条边了,具体看代码。 ```cpp #include <cstdio> #include <cstring> const int maxn=10000+10; const int maxm=100000+10; const int INF=0x3f3f3f3f; int cur[maxn],head[maxn],nxt[maxm<<1],to[maxm<<1],val[maxm<<1];//因为还要存反向边,所以要开两倍 int dep[maxn],inq[maxn]; int n,m,s,t; int tot=1; struct Queue { int a[maxn]; int l,r; Queue() {l=1,r=0;} void push(int x) {a[++r]=x;} void pop() {l++;} int front() {return a[l];} bool empty() {return l>r;} }q; inline int min(int x,int y) {return x<y?x:y;} void add(int u,int v,int w) { nxt[++tot]=head[u]; head[u]=tot; to[tot]=v; val[tot]=w; } bool bfs() { memset(dep, 0x3f, sizeof(dep)); dep[s]=0; q=Queue(); q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for (int i=head[u];i;i=nxt[i]) { int v=to[i];//通向的点 if (val[i]&&dep[v]>dep[u]+1)//如果容量不为0且在u点之前还没有被搜到 { dep[v]=dep[u]+1; q.push(v); } } } return dep[t]<INF;//只要汇点被搜到了,就还有增广路 } int dfs(int u,int minf)//当前位置和目前搜到的最小剩余容量 { if (u==t)//到达汇点 return minf;//返回值不为0即说明可以增广 int used=0;//该点已经使用了的流量 for (int &i=cur[u];i;i=nxt[i])//这里取址是顺便更新cur { int v=to[i]; if (val[i]&&dep[v]==dep[u]+1) { int flow=dfs(v, min(minf-used, val[i]));//能流到t的流量 if (flow) { used+=flow; val[i]-=flow; val[i^1]+=flow; if (used==minf)//该点已达最大流量,不用继续找了 break; } } } return used;//返回该点已使用流量 } 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); } int flag=0,maxflow=0; while(bfs()) { for (int i=1;i<=n;i++)//新的分层图要重新开始 cur[i]=head[i]; maxflow+=dfs(s, INF); } printf("%d\n",maxflow); return 0; } ```