费用流:邻接表实现

虽然说最小费用流10分钟就能敲出来,可是只是练习过裸的邻接矩阵实现。曾经考虑过用邻接表实现,尝试写过方格取数,未果,今日翻出来,发现bug一堆。今天写POJ2315,然后纠结了一个多小时,80%时间都在debug,最后发现是一些低级错误+邻接表的实现错误。

总的来说,邻接表需要存储prev和prevEdge数组,分别记录当前节点的前驱节点和连向当前节点的边在数组中的位置,前者用来往前找,判断有没有到源点,后者用来求增广路的流量、更新流量。

本题做法参考了http://www.cnblogs.com/ylfdrib/archive/2010/08/05/1792735.html

题意简单:FJ有N个农场,M条路,FJ要领朋友游玩,从1走到N,再回到1,不走重复路,每条路长度不一样,问最短路长为多少。

转化为最小费用流来求解,建一源点S,指向节点1,容量为2,距离0,建一汇点T,N节点指向汇点,容量为2,距离为0,表示要有两条路从S到T,其余给定的路,容量为1,边权为路长,表示每条路只走一次。

另外一些低级错误有变量名打错等,还有函数中数组开太大导致堆栈溢出,另外oo的值设的有点小。

网络流中经常要用到常量oo(INF,无限)来表示maxlongint,直接用maxlongint会溢出的,然后我就参考看过的一个程序,设为一个生日,一千多万不小了,不过这题还不行,后面要加个零。我用的是谁的生日呢?自然不是我的,只是隐约在别人谈话中听到可能是她的生日,然后从此这个数字就几乎出现在我的每一个程序间了。

附POJ2315程序:

const
  oo=199305080;
var
  pre,preedge,g,next,c,e,cost,opp:Array[0..1000000] of longint;
  maxflow,p,i,j,k,m,n,mincost,flow,now,x,y,z,size,s,t:longint;


procedure addedge(x,y,z,w:longint);
begin
  inc(size);
  e[size]:=y;
  c[size]:=z;
  cost[size]:=w;
  opp[size]:=size+1;
  next[size]:=g[x];
  g[x]:=size;

  inc(size);
  e[size]:=x;
  c[size]:=0;
  cost[size]:=-w;
  next[size]:=g[y];
  g[y]:=size;
  opp[size]:=size-1;
end;


function spfa:boolean;
var
  q,dist:array[0..10000] of longint;
  flag:array[0..10000] of boolean;
  head,tail,i,j,p:longint;
begin
  head:=0;
  tail:=1;
  q[1]:=s;
  for i:=1 to t do
    dist[i]:=oo;
  dist[s]:=0;
  fillchar(flag,sizeof(flag),0);
  flag[s]:=true;
  while head<tail do
  begin
    inc(head);
    i:=q[head];
    flag[i]:=false;
    p:=g[i];
    while p<>0 do
    begin
      j:=e[p];
      if (dist[j]>dist[i]+cost[p])and(c[p]>0) then
      begin
        dist[j]:=dist[i]+cost[p];
        pre[j]:=i;
        preedge[j]:=p;
        if not flag[j] then
        begin
          inc(tail);
          q[tail]:=j;
          flag[j]:=true;
        end;
      end;
      p:=next[p];
    end;
  end;
  exit(dist[t]<>oo);
end;



procedure init;
begin
  readln(n,m);
  fillchar(g,sizeof(g),0);
  for i:=1 to m do
  begin
    readln(x,y,z);
    addedge(x,y,1,z);
    addedge(y,x,1,z);
  end;
  s:=n+1;
  t:=n+2;
  addedge(s,1,2,0);
  addedge(n,t,2,0);
end;

function min(a,b:longint):longint;
begin
  if a<b then exit(a) else exit(b);
end;


procedure main;
begin
  while spfa do
  begin
    now:=t;
    flow:=oo;
    while now<>s do
    begin
      flow:=min(flow,c[preedge[now]]);
      now:=pre[now];
    end;
    now:=t;
    while now<>s do
    begin
      p:=preedge[now];
      dec(c[p],flow);
      inc(c[opp[p]],flow);
      mincost:=mincost+cost[p]*flow;
      now:=pre[now];
    end;
  end;
end;

procedure print;
begin
  writeln(mincost);
end;


begin

  init;
  main;
  print;
end.

posted on 2011-06-05 20:33  oa414  阅读(356)  评论(0编辑  收藏  举报

导航