USACO 4.2 Drainage Ditches 网络流

题意:有n个点和m条边,给出每条边的最大容量,求从点1到点n最多可以运输多少水。

分析:

这就是典型的最大流问题。下面给出比较形式化的定义:

给定一个有向图G=(V,E),在E集合里的每条边都由三个元素来描述(u,v,c),分别表示起点、终点和容量,并指定一个源点S和一个汇点T,一个流必须满足容量限制和流量守恒。

容量限制:f(u,v)<=c(u,v),形象地理解就是流速不能超过水管的限制。

流量守恒:

 

形象地理解就是中转站不能把水吞掉了。

上面说的一个可行流,而所谓最大流就是要最大化:

其实就是流进汇点的流量。一般我们说一个流的流量都是指流进汇点的流量。

8.2、最大流最小割定理

割的定义:对于边集E’,若满足去掉该边集中所有边以后,源点和汇点不再连通,那么称边集E’为一个割。割的权定义为对应边集中的所有边的容量之和。最小割指的就是权最小的割。

最大流最小割定理实际上就是说:最大流的流量和最小割的权在数值上相等。

8.3、残余网络

残余网络指的其实是把所有边的权更新为w(u,v)=c(u,v)-f(u,v)。

显然初始时有

w(u,v)=c(u,v)

f(u,v)=0

形象地看,就是说这个水管还能容纳多少流量。一般地,我们只需要注意残余网络就可以求出最大流。为了方便下面都用w(u,v)来表示(u,v)这条边的残余流量。

为了实现下面的增广路算法,这里引入反向弧的概念。所谓反向弧,其实是用以修正前面错误的流的一种修正边。对于原图的每条有向边,我们都给它配对一条反向弧,用以修正该条有向边上错误的流。

假设给定的有向边是(u,v),那么给它配对的反向弧就是一条(v,u)这样反向的边并且满足以下这个性质:

w(v,u)=f(u,v)

所以有推论w(v,u)+w(u,v)=c(u,v)

因为流的正反向抵消性质(水从u流到v,再从v流回u,其实就是什么都没发生):

1、如果通过反向弧(v,u)的残余流量增加了流量t,其实相当于f(u,v)=f(u,v)-t,按照上面的性质,其实就是

w(v,u)=w(v,u)-t

w(u,v)=w(u,v)+t

2、如果通过正向弧(v,u)的残余流量增加了流量t,其实相当于f(u,v)=f(u,v)+t,按照上面的性质,其实就是

w(v,u)=w(v,u)+t

w(u,v)=w(u,v)-t

发现了吗?它们是轮换对称的。所以在实际实现中并不需要区分哪条是正向边,哪条是反向弧,假如利用当前边增加了流量t,那么就将当前边的残余流量减去t,再将对应的另一条加上t就可以了。为了方便,我们称正向边和反向弧互为反边,并用op(e)表示e这条边的反边。

8.4、基于最大流最小割定理求最大流的算法(统称Ford-Fulkerson算法)

Ford-Fulkerson是求最大流很经典的算法。该算法就是不断在残余网络中寻找增广路增广,直到找不到增广路为止(也就是说,此时源点和汇点不连通,存在割)。下面给出增广路和增广的含义。

增广路:一条从起始于源点S,终止于汇点T的路径。且必须满足路径上的每条边的残余流量都大于0。

增广:增广是对于一条增广路来说的。令拼接成增广路的有向边组成边集E’。再令,然后对于,进行下面操作:

w(e)=w(e)-delta

w(op(e))=w(op(e))+delta

然后流进汇点T的流就加上delta

代码:

{
ID: ymwbegi1
PROG: ditch
LANG: PASCAL
}

var
  n,m,ans:longint;
  c:array[1..200,1..200] of longint;
  fa:array[1..200] of longint;

procedure init;
var
  i,x,y,z:longint;
begin
  readln(m,n);
  for i:=1 to m do
  begin
    readln(x,y,z);
    inc(c[x,y],z);
  end;
end;

function find(x:longint):boolean;
var
  i:longint;
begin
  if x=n then exit(true);
  for i:=1 to n do
    if (fa[i]=-1)and(c[x,i]>0) then
    begin
      fa[i]:=x;
      if find(i) then exit(true);
    end;
  find:=false;
end;

procedure add;
var
  i,min:longint;
begin
  min:=maxlongint;
  i:=n;
  while i>1 do
  begin
    if c[fa[i],i]<min then min:=c[fa[i],i];
    i:=fa[i];
  end;
  i:=n;
  ans:=ans+min;
  while i>1 do
  begin
    dec(c[fa[i],i],min);
    inc(c[i,fa[i]],min);
    i:=fa[i];
  end;
end;

procedure main;
var
  i:longint;
begin
  for i:=2 to n do
    fa[i]:=-1;
  fa[1]:=0;
  while find(1) do
  begin
    add;
    for i:=2 to n do
      fa[i]:=-1;
    fa[1]:=0;
  end;
end;

begin
  assign(input,'ditch.in');
  assign(output,'ditch.out');
  reset(input);
  rewrite(output);
  init;
  main;
  writeln(ans);
  close(input);
  close(output);
end.


你可能感兴趣的:(USACO 4.2 Drainage Ditches 网络流)