Dinic算法模板
一、Dinic算法的步骤以及复杂度分析
算法步骤: Dinic算法的思想也是分阶段地在层次图中增广。它与最短路径增值算法不同之处是:在Dinic算法中,我们用一个dfs过程代替多次bfs来寻找阻塞流。下面给出其算法步骤:
1、初始化流量,计算出剩余图 2、根据剩余图计算层次图。若汇点不在层次图内,则算法结束 3、在层次图内用一次dfs过程增广 4、转步骤2
下面是dfs的过程:
p=s; While outdegree(s)>0 u=p.top; if u<>t if outdegree(u)>0 设(u,v)为层次图中的一条边; p=p,v; else 从p和层次图中删除点u, 以及和u连接的所有边; else 增广p(删除了p中的饱和边); 令p.top为p中从s可到达的最后顶点; end while
在程序里,p表示找到的增广路径,p.top为路径中的最后一个顶点。一开始,p中只有源点。
整个While循环分为2个操作。如果p的最后一个顶点为汇点,也就是说找到了增广路,那么对p增广,注意到增广后一定有一条或多条p中的边被删除了。这时,我们使增广路径后退至p中从源点可到达的最后一个顶点。
如果p的最后一个顶点不为汇点,那么观察最后那个的顶点u 。若在层次图中存在从u连出的一条边,比如(u,v),我们就将顶点v放入路径p中,继续dfs遍历;否则,点u对之后的dfs遍历就没有用了,我们将点u以及层次图中连到u的所有边删除,并且在p中后退一个点。
Dfs过程将会不断重复这2个操作,直到从源点连出的边全部被删除为止。
二、Dinic 算法模板
void Dinic() { for(;;){ BFS(); if(D[T]==-1)break; int path_n=0; int x=S; memcpy(cur,E,sizeof(cur)); for(;;){ if(x==T){ int mink=-1,delta=INT_MAX; for(int i=0;i<path_n;++i){ if(path[i]->c<delta){ delta=path[i]->c; mink=i; } } for(int i=0;i<path_n;++i){ path[i]->c-=delta; path[i]->back->c+=delta; } path_n=mink; x=path[path_n]->x; } edge* e; for(e=cur[x];e;e=e->next){ if(e->c==0) continue; int y=e->y; if(D[x]+1==D[y]) break; } cur[x]=e; if(e){ path[path_n++]=e; x=e->y; } else{ if(path_n==0) break; D[x]=-1; --path_n; x=path[path_n]->x; } } } }