首先,大家都说dinic好,我就毫不犹豫地先学习一下。
自我认为v^2*e<e^2*v(SAP)。
首先,几个基础知识的tips:
一般情况下在Dinic算法中,我们只记录某一边的剩余流量.
然后,特别将 反向弧 疑难点领出来给大家一句话概括:
- 根据残量网络计算层次图。
- 在层次图中使用DFS进行增广直到不存在增广路
- 重复以上步骤直到无法增广
假设以后你发现这条增广路并不是最优的,反向弧给你一个反悔的机会,让你可以用一条更优的替换掉原来的。
举一个例子:
在这幅图中我们首先要增广1->2->4->6,这时可以获得一个容量为2的流,但是如果不建立4->2反向弧的话,则无法进一步增广,最终答案为2,显然是不对的,然而如果建立了反向弧4->2,则第二次能进行1->3->4->2->5->6的增广,最大流为3.
Comzyh对反向弧的理解可以说是”偷梁换柱“,请仔细阅读:在上面的例子中,我们可以看出,最终结果是1->2->5->6和1->2->4->6和1->3->4->6.当增广完1->2->4->5(代号A)后,在增广1->3->4->2->5->6(代号B),相当于将经过节点2的A流从中截流1(总共是2)走2->5>6,而不走2->4>6了,同时B流也从节点4截流出1(总共是1)走4->6而不是4->2->5->6,相当于AB流做加法.
程序实现:type
node=record
tt,V,next:longint;
end;
const
INF=maxlongint shr 2;
var
cnt,x,y,z,start,stp,n,m,maxflow,i:longint;
level,a,q:array[0..100000]of longint;
e:array[0..200000]of node;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
procedure newnode(x,y,z:longint);
begin
cnt:=cnt+1;
e[cnt].tt:=y;
e[cnt].V:=z;
e[cnt].next:=a[x];
a[x]:=cnt;
end;
procedure init;
var
i,x,y,z:longint;
begin
readln(n,m);
for i:=1 to m do
begin
readln(x,y,z);
newnode(x,y,z);
newnode(y,x,0);
end;
readln(start,stp);
end;
function bfs:boolean;
var
head,tail,i,j:longint;
begin
fillchar(level,sizeof(level),$ff);
head:=0;tail:=1;
q[1]:=start;level[start]:=0;
while head<tail do
begin
head:=head+1;
i:=q[head];
j:=a[i];
while j>0 do
begin
if (e[j].V>0)and(level[e[j].tt]=-1) then
begin
tail:=tail+1;
level[e[j].tt]:=level[i]+1;
q[tail]:=e[j].tt;
end;
j:=e[j].next;
end;
end;
exit(level[stp]>-1);
end;//目的:保证增广路长度最短,加快增广判断速度,避免走回头路
function dfs(x,f:longint):longint;//f为当前剩余流量,x为结点号
var
w,used,i:longint;
begin
if x=stp then exit(f);
used:=0;i:=a[x];//used表示这一层共用的流量数
while i>0 do
begin
if (e[i].v>0)and(level[e[i].tt]=level[x]+1) then
begin
w:=f-used;
w:=dfs(e[i].tt,min(e[i].v,w));//当前边和剩余流量取小值即为可流量
e[i].v:=e[i].v-w;
used:=used+w;
e[i xor 1].v:=e[i xor 1].v+w;//反向弧处理
if used=f then exit(f);//流量已用完
end;
i:=e[i].next;
end;
if used=0 then level[i]:=-1;//没有增广路
exit(used);
end;
procedure solve;
var
maxflow:longint;
begin
maxflow:=0;
while bfs do inc(maxflow,dfs(start,INF));
write(maxflow);
end;
procedure openfile;
begin
assign(input,'dinic.in');reset(input);
assign(output,'dinic.out');rewrite(output);
end;
procedure closfile;
begin
close(input);close(output);
end;
procedure main;
begin
//openfile;
init;
solve;
closfile;
end;
begin
main;
end.
//本文部分摘自comzyh的博客