网络流算法有许多种,最基本的一种方法是Fold-Fulkerson.不过裸奔的Fold-Fulkerson的效率总是不尽如人意.于是各种优化层出不穷.
比较牛X的一个就是基于分层图思想的MPLA(最短路径增值).在层次图里,从源点开始,不管怎么走,总能走到汇点,而且保证是最短路.这是一个非常优美的性质.复杂度证明...找WC2007王欣上论文吧..
于是便有了以下的裸的MPLA程序(附件1).每次计算出一个层次图.然后进行若干次DFS寻找增广路.
Dinic是基于MPLA上的另外一个改进.引入一个新的名词叫做块流,表示在一张剩余图上所有可增广的流量.Dinic在每次计算出层次图后,仅用一次DFS来找出这张图的块流,避免了许多废的搜索状态和回溯状态.详见程序(附件2).
附件一:
{ NetworkFlow_MaxFlow_MPLA } const Infinity=maxlongint; MaxNode=100; MaxEdge=1000; type TEdge=record Start,Target,Next,Capa,Flow:longint; end; var Edge:array[-MaxEdge..MaxEdge]of TEdge; Head,Dist:array[1..MaxNode]of longint; Queue,Pre:array[0..MaxNode]of longint; Used:array[1..MaxNode]of boolean; Stack,StackEdge:array[1..MaxNode]of longint; Source,Sink,EdgeNum,QHead,QTail,TotalFlow,Delta:longint; procedure InsertEdge(FStart,FTarget,FCapa:longint); begin inc(EdgeNum); with Edge[EdgeNum] do begin Start:=FStart; Target:=FTarget; Capa:=FCapa; Next:=Head[FStart]; Head[FStart]:=EdgeNum; end; with Edge[-EdgeNum] do begin Start:=FTarget; Target:=FStart; Next:=Head[FTarget]; Head[FTarget]:=-EdgeNum; end; end; function SetDistLabel:boolean; var Start,Ptr,QHead,QTail:longint; begin fillchar(Dist,sizeof(Dist),0); QHead:=1;QTail:=0; Queue[0]:=Source;Dist[Source]:=1; while QHead>QTail do begin Start:=Queue[QTail];inc(QTail); Ptr:=Head[Start]; while Ptr<>0 do with Edge[Ptr] do begin if (Dist[Target]=0)and(Flow<Capa) then begin Dist[Target]:=Dist[Start]+1; Queue[QHead]:=Target;inc(QHead); end; Ptr:=Next; end; end; SetDistLabel:=(Dist[Sink]>0); end; function FindPath(Start:Longint):boolean; var Ptr:Longint; begin Used[Start]:=True; if Start=Sink then exit(True); Ptr:=Head[Start]; while Ptr<>0 do with Edge[Ptr] do begin if (Dist[Start]+1=Dist[Target])and(not Used[Target])and(Flow<Capa) then if FindPath(Target) then begin Pre[Target]:=Ptr; if Delta>Capa-Flow then Delta:=Capa-Flow; exit(True); end; Ptr:=Next; end; FindPath:=False; end; procedure IncFlow(Delta:Longint); var Now,Ptr:longint; begin Inc(TotalFlow,Delta); Now:=Sink; repeat Ptr:=Pre[Now]; Inc(Edge[Ptr].Flow,Delta); Edge[-Ptr].Flow:=Edge[-Ptr].Flow-Delta; Now:=Edge[Ptr].Start; until Now=Source; end; procedure MPLA; begin while SetDistLabel do begin Delta:=maxlongint; fillchar(Used,sizeof(Used),0); fillchar(Pre,sizeof(Pre),0); while FindPath(Source) do begin IncFlow(Delta); Delta:=maxlongint; fillchar(Used,sizeof(Used),0); fillchar(Pre,sizeof(Pre),0); end; end; writeln(TotalFlow); end; begin end.
附件二:
{ NetworkFlow_MaxFlow_Dinic } const Infinity=maxlongint; MaxNode=100; MaxEdge=1000; type THead=array[1..MaxNode]of longint; TEdge=record Target,Next,Capa,Flow:longint; end; var Edge:array[-MaxEdge..MaxEdge]of TEdge; Head,Bak,Dist:THead; Queue:array[0..MaxNode]of longint; Stack,StackEdge:array[1..MaxNode]of longint; Source,Sink,EdgeNum,QHead,QTail,TotalFlow:longint; procedure AddEdge(A,B,W:longint); begin Inc(EdgeNum); with Edge[EdgeNum] do begin Target:=B; Capa:=W; Next:=Head[A]; Head[A]:=EdgeNum; end; with Edge[-EdgeNum] do begin Target:=A; Next:=Head[B]; Head[B]:=-EdgeNum; end; end; function SetDistLabel:boolean; var Start,Ptr:longint; begin fillchar(Dist,sizeof(Dist),0); QHead:=1;QTail:=0; Queue[0]:=Source;Dist[Source]:=1; while QHead>QTail do begin Start:=Queue[QTail];inc(QTail); Ptr:=Head[Start]; while Ptr<>0 do with Edge[Ptr] do begin if (Dist[Target]=0)and(Flow<Capa) then begin Dist[Target]:=Dist[Start]+1; Queue[QHead]:=Target;inc(QHead); end; Ptr:=Next; end; end; SetDistLabel:=(Dist[Sink]>0); end; function Argument(Top:longint):longint; var i,Delta,T:longint; begin Delta:=Infinity; for i:=1 to Top do with Edge[StackEdge[i]] do if Delta>Capa-Flow then Delta:=Capa-Flow; inc(TotalFLow,Delta); for i:=Top downto 1 do with Edge[StackEdge[i]] do begin inc(Flow,Delta); Dec(Edge[-StackEdge[i]].Flow,Delta); if Flow=Capa then T:=i; end; Argument:=T; end; procedure FindFlow; var Top,Start,Ptr:longint; begin Top:=1;Stack[Top]:=Source; while Top>0 do begin Start:=Stack[Top]; if Start=Sink then begin Top:=Argument(Top-1); Start:=Stack[Top]; end; while Head[Start]<>0 do with Edge[Head[Start]] do begin Ptr:=Head[Start]; Head[Start]:=Next; if (Dist[Target]=Dist[Start]+1)and(Capa>Flow) then begin StackEdge[Top]:=Ptr; Inc(Top,2); Stack[Top-1]:=Target; break; end; end; dec(Top); end; end; procedure Dinic; begin while SetDistLabel do FindFlow; end; begin end.

看完了要说点啥么?