zoukankan      html  css  js  c++  java
  • 关于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.
    
    
    
    
    
    
  • 相关阅读:
    Oracle SQL性能优化
    spring aop简单日志实例
    一个简单的Spring AOP例子
    jQuery的三种$()
    Mac 上的 outlook 一直让输入密码
    idea 中设置成公司规范的代码格式
    Java 中的锁——Lock接口
    TimeUnit枚举类
    Thread.join()的使用
    java线程的等待、通知机制【读书笔记】
  • 原文地址:https://www.cnblogs.com/oldmanren/p/2152567.html
Copyright © 2011-2022 走看看