这里主要介绍一下Dinic算法。。
先介绍几个概念。。
层次图
层次图,就是把原图中的点按照点到源的距离分“层”,只保留不同层之间的边的图。
算法流程
1、根据残量网络计算层次图。
2、在层次图中使用DFS进行增广直到不存在增广路。
3、重复以上步骤直到无法增广。
因为在Dinic的执行过程中,每次重新分层,汇点所在的层次是严格递增的,而n个点的层次图最多有n层,所以最多重新分层n次。在同一个层次图中,因为每条增广路都有一个瓶颈,而两次增广的瓶颈不可能相同,所以增广路最多m条。搜索每一条增广路时,前进和回溯都最多n次,所以这两者造成的时间复杂度是O(nm);而沿着同一条边(i,j)不可能枚举两次,因为第一次枚举时要么这条边的容量已经用尽,要么点j到汇不存在通路从而可将其从这一层次图中删除。综上所述,Dinic算法时间复杂度的理论上界是O(n^2*m)。
附上模板代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int f[201][201],head,tail,dis[201],ans=0,sum=0,n,m,i,x,y,w,q[201];
int bfs()
{
int j,p;
memset(dis,-1,sizeof(dis));
dis[1]=0;
head=0;
tail=1;
q[1]=1;
while (head<tail)
{
head++;
p=q[head];
for (j=1;j<=n;j++)
if (dis[j]<0 && f[p][j]>0)
{
dis[j]=dis[p]+1;
tail++;
q[tail]=j;
}
}
if (dis[n]>0)
return 1;
else
return 0;
}
int dfs(int s,int low)
{
int j,a=0;
if (s==n)
return low;
for (j=1;j<=n;j++)
if (f[s][j]>0 && dis[j]==dis[s]+1 && (a=dfs(j,min(low,f[s][j]))))
{
f[s][j]-=a;
f[j][s]+=a;
return a;
}
return 0;
}
int main()
{
while (scanf("%d %d",&m,&n)!=EOF)
{
memset(f,0,sizeof(f));
for (i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&w);
f[x][y]+=w;
}
ans=0;
while (bfs())
while (sum=dfs(1,0x7fffffff))
ans+=sum;
printf("%d\n",ans);
}
return 0;
}