猴子课堂:网络流的当前弧优化

最近,周围许多人都在聊当前弧优化,于是,我,猴子,为了时髦,也来上一波课!

好了,当前弧优化是什么呢(虽然有些大佬自己推出了,但自己可能也不知道自己加了优化!)?

根据最大流或zkw费用流(不会的可以点开我的博客,我已经置顶了),每次搜过的边基本上都是流不了的了,如果再去搜会十分浪费。

那么,我们可以用一个数组保存每个点的搜到第几条边,每次用k慢慢跳到那跳边,再开始搜,同时,最后,再从第一条边开始搜到没搜的那条边的前一条,可以缩短一些时间!

但是,每次慢慢跳太慢,可以直接记录是哪条边,嘿嘿嘿,就不用前面慢慢找了!

上代码(细节需要注意)!

zkw流(只含递归部分,其他照旧,顺便说一下,MCMF加不了这个优化!):

long long find(int x,ll f)
{
  v[x]=true;
  if(x==ed){v[x]=false;return f;}
  ll ans=0,t=0;
  int k=cur[x],role=cur[x]/*记录一下,为了以后的正义!*/;
  for(;k;k=a[k].next)//搜没搜过的边
  {
    int y=a[k].y;
    if(v[y]==false && a[k].c>0 && d[x]-a[k].k==d[y])
    {
      ans+=t=find(y,mymin(a[k].c,f-ans));
      a[k].c-=t;a[a[k].other].c+=t;cost+=t*a[k].k;
      cur[x]=k;/*纪录*/
      if(ans==f){v[x]=false;return ans;}//当满流输出,这很重要! 
    }
  }
  for(k=last[x];k!=role;k=a[k].next)//搜搜过的边
  {
    int y=a[k].y;
    if(v[y]==false && a[k].c>0 && d[x]-a[k].k==d[y])
    {
      ans+=t=find(y,mymin(a[k].c,f-ans));
      a[k].c-=t;a[a[k].other].c+=t;cost+=t*a[k].k;
      cur[x]=k;/*仔细思考,为什么这里也要记录?*/
      if(ans==f){v[x]=false;return ans;}//当满流输出,这很重要! 
    }
  }
  v[x]=false;
  return ans;
}

  


最大流(Dinic):

int mymin(int x,int y){return x<y?x:y;}
int find(int x,int f)
{
  if(x==ed)return f;
  int s=0,t,role=cur[x],k/*记录*/;
  for(k=cur[x];k;k=a[k].next)//搜没搜过的边
  {
    int y=a[k].y;
    if(h[y]==h[x]+1 && a[k].c>0)
    {
      s+=(t=find(y,mymin(a[k].c,f-s)));
      a[k].c-=t;a[a[k].other].c+=t;
      cur[x]=k;/*记录*/
      if(s==f)return s;//满流输出,这也很重要 
    }
  }
  for(int k=last[x];k!=role;k=a[k].next) //搜搜过的边
  {
    int y=a[k].y;
    if(h[y]==h[x]+1 && a[k].c>0)
    {
      s+=(t=find(y,mymin(a[k].c,f-s)));
      a[k].c-=t;a[a[k].other].c+=t;
      cur[x]=k;/*记录*/
      if(s==f)return s;//满流输出,这也很重要 
    }
  }
  if(s==0)h[x]=0;
  return s;
}

  


好了,现在你懂了吗?

注:上面的图片侵权抱歉!

猜你喜欢

转载自www.cnblogs.com/zhangjianjunab/p/9694678.html