超级久没打过网络流了,感觉要完(van)。。
于是找了个练手的题目来搞一波,决定最近做几道题目巩固一波。
(%%%hzwer网络流24题)
题意很简单,就是模板来着的。。
原本我不准备写SAP的讲解的,然而当我在网上找了半天都没找到稍微漂亮一点的SAP之后我就愤然决定造福人类。
SAP+GAP+弧优化;
我们先来讲解一下SAP
SAP主要过程讲起来简单,但是实现稍微有点复杂。
从源点开始,每一次向外找是否有边可以增广,可以就往下增广①
否则就重标号②
好讲完了(个屁)
这样讲估计是网上的大部分版本,所以说大佬都太牛了,,把我们都当智商150+的人。。
从①开始讲,具体怎么往下增广呢?
设一个fa[i]表示节点i从第fa[i]条边过来,cur[i]表示i的弧。
首先要把当前点的弧更新一波(其实这就是弧优化):
fa[edge[cur[i]].y]:=cur[i];
假如当前弧是最后一条弧(i=n),就把整条增广路遍历一遍,减去最小的容量,然后继续找。
好现在来讲②:
GAP优化:设num[i]表示d[x]=i的x的个数
我们可以很显然的知道如果num[i-1]>0,num[i+1]>0,num[i]=0那么肯定没有增广路了,直接退出就好(因为此时图已经不联通)。
代码:
type node=record
next,x,y,z,op:longint;
end;
var
edge:Array[0..200000]of node;
d,num,fa,cur,head:array[0..200000]of longint;
i,j,k,p,n,m,tot,ans,x,y,z,kk,t:longint;
procedure add(x,y,z:longint);
begin
inc(tot);
edge[tot].x:=x;
edge[tot].y:=y;
edge[tot].z:=z;
edge[tot].op:=tot+1;
edge[tot].next:=head[x];
head[x]:=tot;
inc(tot);
edge[tot].x:=y;
edge[tot].y:=x;
edge[tot].z:=0;
edge[tot].op:=tot-1;
edge[tot].next:=head[y];
head[y]:=tot;
end;
procedure remark(x:longint);
var
min,i:longint;
begin
min:=n-1;
cur[x]:=head[x];
i:=cur[x];
while i<>0 do
with edge[i] do
begin
if (z>0)and(d[y]<min)then min:=d[y];
i:=next;
end;
d[x]:=min+1;
end;
procedure change;
var
i,min:longint;
begin
i:=n;
min:=maxlongint;
while i>1 do
with edge[fa[i]] do
begin
if z<min then min:=z;
i:=x;
end;
ans:=ans+min;
i:=n;
while i>1 do
with edge[fa[i]] do
begin
dec(z,min);
inc(edge[op].z,min);
i:=x;
end;
end;
procedure main;
var
i,j,k:longint;
begin
for i:=1 to n do
cur[i]:=head[i];
num[0]:=n;
ans:=0;
i:=1;
while d[1]<n do
begin
while cur[i]>0 do
with edge[cur[i]] do
if(z>0)and(d[y]+1=d[x])then break
else cur[i]:=next;
if cur[i]=0 then
begin
dec(num[d[i]]);
if num[d[i]]=0 then break;
remark(i);
inc(num[d[i]]);
if i<>1 then i:=edge[fa[i]].x;
end
else begin
fa[edge[cur[i]].y]:=cur[i];
i:=edge[cur[i]].y;
if i=n then
begin
change;
i:=1;
end;
end;
end;
end;
begin
readln(t);
for kk:=1 to t do
begin
tot:=0;
fillchar(d,sizeof(d),0);
fillchar(edge,sizeof(edge),0);
fillchar(fa,sizeof(fa),0);
fillchar(num,sizeof(num),0);
fillchar(head,sizeof(head),0);
readln(n,m);
for i:=1 to m do
begin
readln(x,y,z);
add(x,y,z);
end;
ans:=0;
main;
writeln('Case ',kk,': ',ans);
end;
end.