这里以poj1459为例,模板中运用了 当前弧优化 ,即如果某次搜索中发现某条边不能流通,就把这条边舍去,以免重复搜索浪费时间
对于分层图的解释:引自白书:“每次寻找最短增广路,因为最短增广路长度在增广过程中始终不会变短。我们可以先进行一次宽度优先搜索,然后考虑由近距离点指向远距离点组成分层图,在上面进行深搜寻找最短增广路。如果找不到新的增广路了,说明最短增广路的长度变长了,或者不存在增广路了,于是通过宽搜寻找构成新的分层图。每一步构造分层图复杂度O(E),每一步完成后至少增广路长度至少增加1,且增广路长度不会超过V-1则,最多O(V)步,这样就能保证复杂度小于等于O(E *V *V)”
若想要认真学习该算法,建议看这位dalao的文章:
https://www.cnblogs.com/SYCstudio/p/7260613.html
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<stdlib.h>
using namespace std;
int n,ns,nt,m,iter[105],dis[105];
int tot,head[105],nex[40005],to[40005],f[40005],ni[40005];
queue<int>q;
void add(int u,int v,int w)//建图加边,每次建图时,建一条反向弧,并记录某个弧的反向弧编号
{
tot++;//建正向弧
to[tot]=v;
f[tot]=w;
nex[tot]=head[u];
head[u]=tot;
tot++;//建反向弧
to[tot]=u;
f[tot]=0;
nex[tot]=head[v];
head[v]=tot;
//互相记录编号
ni[tot]=tot-1;
ni[tot-1]=tot;
}
void bfs(int s)//bfs对图按照与源点的距离进行分层
{
dis[s]=0;
q.push(s);
while(!q.empty())
{
int now=q.front();q.pop();
for (int i=head[now];i!=0;i=nex[i])
{
int v=to[i];
if (dis[v]==-1 && f[i]>0)
{
dis[v]=dis[now]+1;
q.push(v);
}
}
}
}
int dinic(int x,int t,int tf) //记录本次最多能流多大
{
if (x==t) return tf;
for (int i=iter[x];i!=0;i=nex[i])
{
iter[x]=i;//当前弧优化
int v=to[i];
if (dis[v]!=dis[x]+1 || f[i]==0) continue;//不流通的情况就continue
int tmp=dinic(v,t,min(tf,f[i]));//如果可以从这条边拓展下去可以流通
if (tmp>0)
{
f[i]-=tmp;
f[ni[i]]+=tmp;
return tmp;
}
}
return 0;
}
int max_f(int s,int t)//求最大流
{
int ans=0;
while(1)
{
for (int i=0;i<=n+2;i++)//初始化
iter[i]=head[i],dis[i]=-1;
bfs(s);
if (dis[t]==-1) break;//说明已经没有能到达终点的通路
while(1)
{
int tmpf=dinic(s,t,9990000);
if (tmpf<=0) break;
ans+=tmpf;
}
}
return ans;
}
char p1,p2,p3;
int main()
{
while(scanf("%d%d%d%d",&n,&ns,&nt,&m)!=EOF)
{
tot=0;
for (int i=0;i<=n+2;i++)
head[i]=0;
for (int i=1,x,y,z;i<=m;i++)
{
cin>>p1>>x>>p2>>y>>p3>>z;
if (x==y) continue;
add(x,y,z);
}
for (int i=1,x,y;i<=ns;i++)
{
cin>>p1>>x>>p2>>y;
add(n+1,x,y);
}
for (int i=1,x,y;i<=nt;i++)
{
cin>>p1>>x>>p2>>y;
add(x,n+2,y);
}
int ans=max_f(n+1,n+2);
printf("%d\n",ans);
}
}