【问题描述】

      在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。

      农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。

      根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。

 

【解题报告】

     最近爱上做裸题了。。。裸的最大流,本菜用极度精简的SAP做的。代码只能背(一个符号不能错),想理解会死人。

 1 {
2 允许弧:(u,v)满足d[u]+1=d[v]
3 如果一条弧(u,v)不是允许弧,则它重新成为允许弧的必要条件事d[u]改变
4 }
5 program ditch_sap
6 var
7 g,c,f:array[0..1000,0..1000] of longint; {残量网络}
8 vd,d:array[0..1000] of longint; {d:标号距离, vd:数组vd[i]记录标号距离为i的顶点个数}
9 m,n,x,y,z,flow,ans,i:longint;
10 function min(a,b:longint):longint;
11 begin
12 min:=a; if a>b then min:=b;
13 end;
14
15 function dfs(u,flow:longint):longint;
16 var
17 v,tmp:longint;
18 begin
19 if u=n then exit(flow); {找到增广路}
20
21 dfs:=0; {min_d:u在残量网络里相通的边的最小标号距离,初始不能变为maxint}
22 for v:=1 to n do if (g[u,v]>0 ) and (d[u]=d[v]+1) then {如果是允许弧}
23 begin
24 tmp:=dfs(v,min(flow-dfs,g[u,v])); {如果找到,增广}
25 dec(g[u,v],tmp);
26 inc(g[v,u],tmp);
27 if c[u,v]>0 then inc(f[u,v],tmp) else dec(f[v,u],tmp); {记录好的流量}
28 dfs:=dfs+tmp;
29 if dfs=flow then exit(dfs);
30 end;
31 if d[1]>=n then exit; {如果源点的标号距离大于n,即不存在增广路,这一步放在重标号之前}
32 dec(vd[d[u]]);
33 if vd[d[u]]=0 then d[1]:=n; {如果该标号距离的顶点是唯一的,那么删除后图出现断层} {这个地方只能写=,不能写<=,我蛋疼}
34 d[u]:=d[u]+1;
35 inc(vd[d[u]]);
36 end;
37 begin
38 assign(input,'ditch.in'); reset(input);
39 assign(output,'ditch.out'); rewrite(output);
40 readln(m,n);
41 for i:=1 to m do
42 begin
43 read(x,y,z);
44 inc(g[x,y],z);
45 inc(c[x,y],z);
46 end;
47 vd[0]:=n;
48 while d[1]<n do
49 begin
50 flow:=dfs(1,maxlongint);
51 inc(ans,flow);
52 end;
53 writeln(ans);
54 close(input); close(output);
55 end.
56