网络流是一种神奇的东西,它的问题大致为:你在S号城市拥有很多物资,现在你要把它们运到城市T,除此之外还有很多其他城市,有些城市间有道路,有些没有,且每条道路都有所运物资的最大量。你可以先把一些物资从S直接运向T(必须S到T有道路且运的物资总量小于这条道路的最大量),再把另一些运往A,再从A运向T(须S到A,A到T有道路,且运送物资量都小于这两条道路的最大量)
最大流
顾名思义就是求从S到T最多运多少物资,这个问题理解了也不难。
不断重复以下步骤:
1.维护一个队列,用类似SPFA的方法求出从S到每一个城市运送的可能的物资数(不为0,也不一定最大),并记录其父节点;
2.判断是否有物资运到T城市,如果没有就退出循环;
3.如果有物资运到T城市,就把当前记录的运到T的物资累加入总计,并把本次记录的从S到T的路径上每一条道路的最大量减去当前记录的值(代表吧这些物资运过去了)。
这个方法叫增广路。
代码如下(云神教的):
int sap(int p,int f){ if (p==ty) return f; int h=0; for (int i=d[p];i;i=bi[i].ne) if ((bi[i].l)&&(c[bi[i].y]+1==c[p])){ int q=sap(bi[i].y,min(f-h,bi[i].l)); //printf("%d %d ",bi[i].y,q); h+=q; bi[i].l-=q;bi[bi[i].pa].l+=q;d[p]=i;//当前弧优化 if (h==f) return f; } if (c[sy]>=no) return h;//分层 g[c[p]]--; if (!(g[c[p]])) c[sy]=no; c[p]++; g[c[p]]++;d[p]=la[p]; return h; }
最小割
这是指摧毁掉一些道路,使得不可能有物资运从S到T,且代价最小。
同样是增广路算法,最后一个循环做完后有标记的点和未标记的点分为两个点集,删去连接两个点集的点,即为最小割。
费用流
在最大流的基础上,每条道路都有一定费用,要求在物资最多的前提下费用最小。
只须在增广路中加一点判断使费用最小就行了。
完……