关于zkw流的一些感触

作为一种特殊的网络流——费用流,是在原最大流的基础上,每条边给个权(费用),并让你使得每条边的流量*费用的总和最小。

一种基于贪心的方法就是每次都找最小费用的路径增广。所以就有了SPFA流:每次对图SPFA一遍,按最小费用的路径增广即可。而可以看出,SPFA每次只增广一遍,感觉是十分浪费的。

于是,就有zkw很牛B的发明了zkw流。其思路与最大流的ISAP算法类似。

在我看来,起码zkw流是不会慢于SPFA流的。对于费用很小很集中,瓶颈容量小但总容量大的图,因为zkw流的多路增广的优势,其效率远远快于SPFA流。

而我在今天之前,一直犯了一个错误,使zkw流变得比较慢(或者是很慢)。

每次DFS时,对于一个点i,我们是要另外记一个数组来记下当前扫到了那条边。如果有第二次来,就从上一次的那条边继续下去。而我第一次写时自作聪明,直接每次都从开始扫起。对于一般的稀疏图,效率的差距还不是很大,但是遇到了下面两题的那种特殊图,就果断TLE了。破碎的心

两题都是一个顶点分配求最值问题。对于费用会变化的边,因为费用呈单调上升,所以每次容量更改时顺便把费用改一下就行了。

TYVJ(1184)

WC jsb

var n,m,i,j,k,l,p,x,y,tmp,ans:longint;
      t,cc:array[1..2000] of longint;
      e,c,b,w:array[-20000..20000] of longint;
      first,first2,last,dis,f:array[1..5002] of longint;
      v,o:array[1..5002] of boolean;
function pow(x,y,z:longint):longint;
var t:longint;
begin
pow:=x;
for t:=1 to z do pow:=pow*y;
end;
procedure add(x,y,z,q:longint);
begin
p:=p+1;
e[p]:=y;c[p]:=z;w[p]:=q;
if first[x]=0 then first[x]:=p else b[last[x]]:=p;last[x]:=p;
e[-p]:=x;c[-p]:=0;w[-p]:=-q;
if first[y]=0 then first[y]:=-p else b[last[y]]:=-p;last[y]:=-p;
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function zkw(i,flow:longint):longint;
var r,d,k,l:longint;
begin
if i=n+m+2 then begin ans:=ans+dis[i]*flow;exit(flow);end;
v[i]:=true;o[i]:=true;
r:=flow;
while first[i]<>0 do
begin
k:=first[i];
if c[k]>0 then
begin
  l:=dis[i]+w[k]-dis[e[k]];
  if l<f[e[k]] then f[e[k]]:=l;
  if (l=0)and(not o[e[k]]) then
  begin
     if r<c[k] then d:=zkw(e[k],r)
	           else d:=zkw(e[k],c[k]);
     if (k>0)and(k<=n) then w[k]:=pow(cc[k],maxint-c[k]+2,t[k])-pow(cc[k],maxint-c[k]+1,t[k]);
     c[k]:=c[k]-d;c[-k]:=c[-k]+d;
     r:=r-d;
     if r=0 then break;
  end;
end;
first[i]:=b[first[i]];
end;
o[i]:=false;
exit(flow-r);
end;

begin
readln(n,m);
for i:=1 to n do read(t[i]);readln;
for i:=1 to n do read(cc[i]);readln;
p:=0;
for i:=1 to n do add(m+i+1,m+n+2,maxint,pow(cc[i],1,t[i]));
for i:=1 to m do add(1,i+1,1,0);
for i:=1 to m do
begin
readln(x,y);
add(i+1,m+x+1,1,0);
add(i+1,m+y+1,1,0);
end;

fillchar(o,sizeof(o),false);
fillchar(dis,sizeof(dis),0);
ans:=0;
first2:=first;
repeat
filldword(f,sizeof(f) div 4,maxlongint);
fillchar(v,sizeof(v),false);
first:=first2;
zkw(1,maxlongint);
tmp:=maxlongint;
for i:=1 to n+m+2 do
if (not v[i])and(f[i]<tmp) then tmp:=f[i];
if tmp=maxlongint then break;
for i:=1 to n+m+2 do
if not v[i] then dis[i]:=dis[i]+tmp;
until false;
writeln(ans);
end.
var n,i,j,k,l,p,p1,x,total,mina,ppp,ti:longint;
    a,tt:array[1..100,1..100] of longint;
    e,c,b,w:array[-20000..20000] of longint;
    first,last,dd,d,f:array[0..5100] of longint;
    o,v:array[0..5100] of boolean;
procedure add(x,y,z,q:longint);
begin
//writeln(x,' ',y,' ',z,' ',q);
p:=p+1;
e[p]:=y;c[p]:=z;w[p]:=q;b[p]:=last[x];last[x]:=p;
//writeln(p,':',x,' ',y,' ',b[p]);
e[-p]:=x;c[-p]:=0;w[-p]:=-q;b[-p]:=last[y];last[y]:=-p;
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function zkw(i,flow:longint):longint;
var k,r,dd,l:longint;
begin
if i=p1+1 then begin total:=total+d[i]*flow;exit(flow);end;

v[i]:=true;o[i]:=true;r:=flow;

while first[i]<>0 do
begin
k:=first[i];
if (c[k]>0)and(not o[e[k]]) then
begin
inc(ti);
l:=d[i]+w[k]-d[e[k]];
if l<f[e[k]] then f[e[k]]:=l;
if l=0 then
begin
  if r=0 then break;
  //if not v[e[k]] then
  if c[k]<r then dd:=zkw(e[k],c[k])
            else dd:=zkw(e[k],r);
  r:=r-dd;
  c[k]:=c[k]-dd;c[-k]:=c[-k]+dd;
  if (dd>0)and(abs(k)>=ppp) then begin w[k]:=w[k]+2;w[-k]:=w[-k]-2;end;
  if r=0 then break;
end;
end;
first[i]:=b[first[i]];
end;
o[i]:=false;
exit(flow-r);
end;


begin
assign(input,'jsb.in');
assign(output,'jsb.out');
reset(input);rewrite(output);

readln(n);
fillchar(dd,sizeof(dd),0);
p:=0;p1:=n;
for i:=1 to n do
for j:=1 to n do
begin
read(x);
a[i,j]:=x;
if x=1 then inc(dd[j]);
if (x=2)and(i<j) then inc(p1);
end;


total:=0;
for i:=1 to n do total:=total+sqr(dd[i]);
p1:=n;
for i:=1 to n do
for j:=i+1 to n do
if a[i,j]=2 then
begin
p1:=p1+1;
add(0,p1,1,0);
add(p1,i,1,0);tt[i,j]:=p;
add(p1,j,1,0);tt[j,i]:=p;
end;

ppp:=p+1;
for i:=1 to n do add(i,p1+1,maxlongint,(dd[i]+1)*2-1);

fillchar(d,sizeof(d),0);
fillchar(o,sizeof(o),false);
repeat
filldword(f,sizeof(f) div 4,maxlongint);
fillchar(v,sizeof(v),false);
first:=last;
zkw(0,maxlongint);
mina:=maxlongint;
for i:=0 to p1+1 do if (not v[i])and(f[i]<mina) then mina:=f[i];
if mina=maxlongint then break;
for i:=0 to p1+1 do if not v[i] then d[i]:=d[i]+mina;
until false;
//writeln(total);
//writeln(ti);
writeln(n*(n-1)*(n-2) div 6+n*(n-1)/4-total/2:0:0);

{for i:=1 to n do
begin
if a[i,1]=2 then write(c[tt[i,1]]) else write(a[i,1]);
for j:=2 to n do
if a[i,j]=2 then write(' ',c[tt[i,j]]) else write(' ',a[i,j]);
writeln;
end;}

close(input);close(output);
end.





原文地址:https://www.cnblogs.com/oldmanren/p/2152567.html