最近,周围许多人都在聊当前弧优化,于是,我,猴子,为了时髦,也来上一波课!
好了,当前弧优化是什么呢(虽然有些大佬自己推出了,但自己可能也不知道自己加了优化!)?
根据最大流或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; }
好了,现在你懂了吗?
注:上面的图片侵权抱歉!