网络流算法有许多种,最基本的一种方法是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.

, ,

看完了要说点啥么?