最大流
最大流问题,是网络流理论研究的一个基本问题,求网络中一个可行流f*,使其流量v(f)达到最大, 这种流f称为最大流,这个问题称为(网络)最大流问题。最大流问题是一个特殊的线性规划问题,就是在容量网络中,寻找流量最大的可行流。(来自百度百科)
ISAP
ISAP是dinic算法的优化,把dinicO(n^2*m)优化到O(nm),最重要的是ISAP比dinic短!ISAP比dinic短!ISAP比dinic短!(重要的事情说三遍)
Dinic算法中,我们需要每次搜索出层次图,而在ISAP中,我们只需要每次dfs的过程中修改距离标号。具体来说,我们用d[x]d[x]表示残余网络上xx到汇点tt的最短距离,我们每次沿着d[x]=d[v]+1d[x]=d[v]+1的路增广。如果点xx的出边的点没有发现满足这个条件的那么就说明当前的最短路已经过时了,我们需要修改距离标号。修改距离标号,就是让xx可以至少有一个点可以增广,所以取所有d[v]d[v]中最小的那个加一即可。这样增广下去,当d[s]d[s],即ss到tt的距离大于等于nn的时候,就说明至少有一个点经过了两次,即不存在增广路了,这个时候算法退出。
图解(虽然说也许看了图依然不懂,但应该还有一点用处的)
自己做的gif,不要骂制作烂。
代码(#101. 最大流(www.loj.ac))
#include<bits/stdc++.h> #define inf (1ll<<57) #define N 100009 #define M 1000009 #define int long long using namespace std; void read(int&n) { int k=1;n=0;char ch=getchar(); while(!('0'<=ch&&ch<='9')&&ch!='-')ch=getchar(); if(ch=='-')k=-1,ch=getchar(); while('0'<=ch&&ch<='9')n=n*10+ch-48,ch=getchar(); n*=k; } int to[M],head[N],nxt[M],val[M],tot=1; void add(int x,int y,int z){ to[++tot]=head[x],nxt[tot]=y,val[tot]=z,head[x]=tot; } void adds(int x,int y,int z){add(x,y,z),add(y,x,0);} int a[N],gap[N],hea[N],que[N],be,ed,s,t,x,y,z; void init() { memset(a,0,sizeof(a)); memset(gap,0,sizeof(gap)); memcpy(hea,head,sizeof(hea)); ++gap[a[que[be=ed=1]=t]=1]; while(be<=ed){ x=que[be++]; for(int i=head[x];i;i=to[i]) if(!a[nxt[i]]) ++gap[a[que[++ed]=nxt[i]]=a[x]+1]; } } int n,m,ans; int isap(int k,int fl) { if(k==t)return fl; if(!fl)return 0; int tmp,flow=0; for(int&i=hea[k];i;i=to[i]) if(a[k]==a[nxt[i]]+1&&(tmp=isap(nxt[i],min(fl,val[i])))) { flow+=tmp,fl-=tmp,val[i]-=tmp,val[i^1]+=tmp; if(!fl)return flow; } if(!(--gap[a[k]]))a[s]=n+1; ++gap[++a[k]],hea[k]=head[k]; return flow; } signed main() { read(n),read(m); read(s),read(t); for(int i=m;i;i--) read(x),read(y),read(z),adds(x,y,z); init(); while(a[s]<=n) ans+=isap(s,inf); printf("%lld ",ans); return 0; }