作为一种特殊的网络流——费用流,是在原最大流的基础上,每条边给个权(费用),并让你使得每条边的流量*费用的总和最小。
一种基于贪心的方法就是每次都找最小费用的路径增广。所以就有了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.