起于源点s,止于汇点t,解决最大流问题的过程就是不断寻找增广路径的过程。最大流问题专用术语先一一解释。
1.增广路径:从源点到汇点不一定只有一条路,要想做到流到汇点的流量最大,必须使得每一条能到汇点的路径都能被流经。每一条从源点到汇点的路径便是一条增广路径。
2.反向弧:每从一点到达另一点,都需要在相反的方向上设置一条反向边,每条反向边的作用可以理解为给算法一个可以反悔的机会。
3.残余网络:当每从一点到达其下一个点时,这个点可以经过的流量需要减去实际经过的流量,以便往后寻找增广路径时不会出现流量大于可行流量的情况。这样处理过的流量网络便是残余网络。
最大流问题较为高效的方法是Dinic和SAP,Dinic方法结合了中级篇讲的BFS和DFS算法的优势,通过BFS算法寻找增广路径,DFS算法求得每条可行流的最大值。
先来讲讲如何寻找增广路径。
增广路径用BFS算法。设置数组dis[ ],表示每个点距离源点的距离。初始化为-1,源点dis[ 1 ] =1,之后开始遍历,一要是能到达且该点对应dis值为-1,便将该点dis值设为前点dis值加1。这个有什么用?等到了DFS的时候就知道了 。如果最终汇点的dis值不为-1,及说明会点可以到达,增广路径存在,返回true,否则返回false。
int BFS()
{
queueque;
memset(dis,-1,sizeof(dis));//每次寻找增广路径都需要将dis数组重置
dis[1]=0; //起始点为0
que.push(1);
while(!que.empty())
{
int cur=que.front();
que.pop();
for(int i=1;i<=n;i++)
{
if(c[cur][i]&&dis[i]<0) //如果可行且该点尚未被标注
{
dis[i]=dis[cur]+1; //改变dis值
que.push(i); //入队继续遍历
}
}
}
if(dis[n]>0) return true; //汇点值不为-1,说明增广路径存在
return false; //反之不存在
}
int DFS(int point,int MAX) //point为当前遍历的节点,MAX为最大可行流量,MAX初始为INF
{
int a;
if(point==n) return MAX; //当前点为汇点时返回即可
for(int i=1;i<=n;i++)
{
//当路径可行,对终点进行DFS
if(c[point][i]&&dis[i]==dis[point]+1&&(a=DFS(i,min(MAX,c[point][i]))))
{
c[point][i]-=a; //构建残余网络
c[i][point]+=a; //建立反向弧
return a;
}
}
return 0;
}
题意:m条路径,n个点,每条路径输入起点,终点和流量,求源点到汇点的最大流量
分析:这题直接套模板就行
#include
#include
#include
#include
#define INF 9999999
using namespace std;
int n,m;
int c[205][205],dis[205]; //c数组为原始网络
int BFS()
{
queueque;
memset(dis,-1,sizeof(dis));//每次寻找增广路径都需要将dis数组重置
dis[1]=0; //起始点为0
que.push(1);
while(!que.empty())
{
int cur=que.front();
que.pop();
for(int i=1;i<=n;i++)
{
if(c[cur][i]&&dis[i]<0) //如果可行且该点尚未被标注
{
dis[i]=dis[cur]+1; //改变dis值
que.push(i); //入队继续遍历
}
}
}
if(dis[n]>0) return true; //汇点值不为-1,说明增广路径存在
return false; //反之不存在
}
int DFS(int point,int MAX) //point为当前遍历的节点,MAX为最大可行流量,MAX初始为INF
{
int a;
if(point==n) return MAX; //当前点为汇点时返回即可
for(int i=1;i<=n;i++)
{
//当路径可行,对终点进行DFS
if(c[point][i]&&dis[i]==dis[point]+1&&(a=DFS(i,min(MAX,c[point][i]))))
{
c[point][i]-=a; //构建残余网络
c[i][point]+=a; //建立反向弧
return a;
}
}
return 0;
}
int main()
{
while(cin>>m>>n)
{
memset(c,0,sizeof(c));
while(m--) //构建原始网络
{
int u,v,w;
cin>>u>>v>>w;
c[u][v]+=w;
}
int sum=0;
while(BFS()) //当增广路径存在进行DFS
{
int s=DFS(1,INF); //从源点出发,初始最大可行流设为无穷大
sum+=s; //结果加上得到的最大可行流
}
cout<