我数次想要写网络流的博客,但是东西太多了,我又太颓了,以至于一直没有写……
这次就写一个ISAP吧!学了ISAP和(自己的)Dinic一比,感觉还是快了许多的!(不是和loj上前几名的大佬的Dinic比)
最大流还有一点要吐槽的,就是当前弧优化不知道为什么写不对(每次加过之后Dinic就会变慢……),所以一直就没加当前弧优化……
由于本人太懒了,不想写一遍思路,具体请参见注释。
注:代码注释中"和Dinic相同"之类的字眼,不用担心,我之后会加一篇Dinic的博客。
#include<cstdio> #include<cstring> #define min(a,b) (a<b?a:b) #define MXN 10000+2 #define MXM 100000+10 int v[2*MXM],flow[2*MXM],fst[MXN],nxt[2*MXM]; //----邻接表 int layer[MXN],gap[MXN]; //----网络图信息:layer-层、gap-优化数组 int etop,S,T,n; //----etop边数,S源点,T汇点,n点数 int queue[MXN+100],head,tail;//----手打队列 void AddEdge(int x,int y,int z){ //----加边函数:每次连续加正反两条边 //----从0开始加边,可以用位运算瞎搞,第i条边的反向边为第i^1条边 v[etop]=y; flow[etop]=z; nxt[etop]=fst[x]; fst[x]=etop++; v[etop]=x; flow[etop]=0; nxt[etop]=fst[y]; fst[y]=etop++; return; } void GraphInit(){ //----建图(残量网络) memset(fst,-1,sizeof(fst)); memset(nxt,-1,sizeof(nxt)); int m,x,y,z; scanf("%d%d%d%d",&n,&m,&S,&T); etop=0; for(int i=0;i<m;i++){ scanf("%d%d%d",&x,&y,&z); AddEdge(x,y,z); } return; } void ISAPInit(){ //----ISAP初始化,上来从汇点bfs分一下层,用于之后dfs //----同时加gap优化 memset(layer,-1,sizeof(layer)); memset(gap,0,sizeof(gap)); queue[tail++]=T; layer[T]=0; gap[layer[T]]++; while(head<tail){ int x=queue[head++]; for(int y=fst[x];y!=-1;y=nxt[y]){ if(layer[v[y]]==-1){ layer[v[y]]=layer[x]+1; gap[layer[v[y]]]++; queue[tail++]=v[y]; } } } return; } int ISAPDfs(int now,int f){ //----ISAP求解最大流的主要函数 //----Dfs到汇点直接返回 if(now==T) return f; int sum=0,temp; for(int y=fst[now];y!=-1;y=nxt[y]){ //----和Dinic的Dfs相同 if(layer[v[y]]+1==layer[now]){ temp=ISAPDfs(v[y],min(flow[y],f)); sum+=temp; f-=temp; flow[y]-=temp; flow[y^1]+=temp; if(f==0) return sum; } } //----gap优化的核心,也算是ISAP很快的主要原因 //----gap记录每一层的点数 if(--gap[layer[now]]==0) layer[S]=n; ++gap[++layer[now]]; //----首先,这次Dfs后,这一个点满足分层条件的所有边都已经增广 //----因此这个点已经不用在这一层待着了,但是由于我们不知道他可以到哪一层,将层数++,下次Dfs再试 //----同时将原层数的gap--。优化在于,如果减后gap==0,那么就会出现断层,之后就没有满足分层的增广路了 //----就可以不用ISAP了,就将S的layer置为n return sum; } int ISAP(){ int ans=0; ISAPInit(); while(layer[S]<n) ans+=ISAPDfs(S,0x7fffffff); //----S的层是n的话,表示一定出现了断层,或者已经没有从S出发的增广路了(即进行过layer[S]++) //----因此不能再增广了,一定达到了最大流,退出ISAP即可。 return ans; } int main(){ GraphInit(); printf("%d",ISAP()); return 0; }
代码交到洛谷模板题上可AC。