网络流 最大流dinic算法解释
关于最大流的求解
- 找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0(注意是小于而不是小于等于,这意味着这条边还可以分配流量),这条路径便称为增广路
- 找到这条路径上最小的F[u][v](我们设F[u][v]表示u->v这条边上的残量即剩余流量),下面记为flow
- 将这条路径上的每一条有向边u->v的残量减去flow,同时对于起反向边v->u的残量加上flow
- 重复上述过程,直到找不出增广路,此时我们就找到了最大流
这个算法是基于增广路定理(Augmenting Path Theorem)
引入dinic算法
dinic算法实质上加上了分层图的思想,即每次更新残量网络上最短路的增广路。
参考一个比较优秀的代码
一些变量的定义
int s,t;//源点和汇点
int cnt;//边的数量,从0开始编号。
int Head[maxN];//每一个点最后一条边的编号
int Next[maxM];//指向对应点的前一条边
int V[maxM];//每一条边指向的点
int W[maxM];//每一条边的残量
int Depth[maxN];//分层图中标记深度
Dinic主过程:
int Dinic()
{
int Ans=0;//记录最大流量
while (bfs())
{
while (int d=dfs(s,inf))
Ans+=d;
}
return Ans;
}
bfs分层图过程
bool bfs()
{
queue<int> Q;//定义一个bfs寻找分层图时的队列
while (!Q.empty())
Q.pop();
memset(Depth,0,sizeof(Depth));
Depth[s]=1;//源点深度为1
Q.push(s);
do
{
int u=Q.front();
Q.pop();
for (int i=Head[u];i!=-1;i=Next[i])
if ((W[i]>0)&&(Depth[V[i]]==0))//若该残量不为0,且V[i]还未分配深度,则给其分配深度并放入队列
{
Depth[V[i]]=Depth[u]+1;
Q.push(V[i]);
}
}
while (!Q.empty());
if (Depth[t]==0)//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
return 0;
return 1;
}
dfs寻找增广路过程
int dfs(int u,int dist)//u是当前节点,dist是当前流量
{
if (u==t)//当已经到达汇点,直接返回
return dist;
for (int i=Head[u];i!=-1;i=Next[i])
{
if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))//注意这里要满足分层图和残量不为0两个条件
{
int di=dfs(V[i],min(dist,W[i]));//向下增广
if (di>0)//若增广成功
{
W[i]-=di;//正向边减
W[i^1]+=di;反向边加
return di;//向上传递
}
}
}
return 0;//否则说明没有增广路,返回0
}
把上面的内容都封装到类中:
在此处加上了当前弧优化,即每次不从1开始搜,而是从cur[i]开始。
class Graph
{
private:
int cnt;
int Head[maxN];
int Next[maxM];
int W[maxM];
int V[maxM];
int Depth[maxN];
int cur[maxN];//cur就是记录当前点u循环到了哪一条边
public:
int s,t;
void init()
{
cnt=-1;
memset(Head,-1,sizeof(Head));
memset(Next,-1,sizeof(Next));
}
void _Add(int u,int v,int w)
{
cnt++;
Next[cnt]=Head[u];
Head[u]=cnt;
V[cnt]=v;
W[cnt]=w;
}
void Add_Edge(int u,int v,int w)
{
_Add(u,v,w);
_Add(v,u,0);
}
int dfs(int u,int flow)
{
if (u==t)
return flow;
for (int& i=cur[u];i!=-1;i=Next[i])
{
if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))
{
int di=dfs(V[i],min(flow,W[i]));
if (di>0)
{
W[i]-=di;
W[i^1]+=di;
return di;
}
}
}
return 0;
}
int bfs()
{
queue<int> Q;
while (!Q.empty())
Q.pop();
memset(Depth,0,sizeof(Depth));
Depth[s]=1;
Q.push(s);
do
{
int u=Q.front();
Q.pop();
for (int i=Head[u];i!=-1;i=Next[i])
if ((Depth[V[i]]==0)&&(W[i]>0))
{
Depth[V[i]]=Depth[u]+1;
Q.push(V[i]);
}
}
while (!Q.empty());
if (Depth[t]>0)
return 1;
return 0;
}
int Dinic()
{
int Ans=0;
while (bfs())
{
for (int i=1;i<=n;i++) cur[i]=Head[i];
while (int d=dfs(s,inf))
{
Ans+=d;
}
}
return Ans;
}
};