Dinic是一种利用增广路径解决最大流的算法,主要利用BFS寻找增光路径直到无法增广
首先是搭边
struct ed
{
int to,cap,next; //cap表示该边剩余容量
}e[maxm];
int level[maxn],head[maxn];
void add(int from,int to,int cap) //利用堆储存
{
e[cnt].to=to;
e[cnt].cap=cap;
e[cnt].next=head[from];
head[from]=cnt++;
swap(from,to); //建立反向边
e[cnt].to=to;
e[cnt].cap=0;
e[cnt].next=head[from];
head[from]=cnt++;
}
反向边有什么用?
反向边是搭边过程中重要的一环,一般来说反向边的from与to跟原边相反,剩余容量为0,这样在增广过程中若发现更优解我们就可以使流量从反向边回流。
接下来利用BFS寻找增广路
bool bfs()
{
memset(level,-1,sizeof(level));
level[Start]=0; //level记录层数为DFS做准备
queue<int>q;
q.push(Start);
while(!q.empty())
{
int i,u=q.front();
q.pop();
for(i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].cap>0&&level[v]==-1) //若该边还有剩余容量并且没有被遍历
{
level[v]=level[u]+1;
q.push(v);
}
}
}
return level[End]!=-1; //是否找到增广路
}
找到增广路就对其进行增广
int dfs(int u,int f) //当前点与当前流量
{
if(u==End||!f) return f;
int k,i;
for(i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].cap>0&&level[u]+1==level[v]) //沿level进行增广
{
k=dfs(v,min(f,e[i].cap));
if(k>0)
{
e[i].cap-=k; //当前边边减去流量k
e[i^1].cap+=k; //当前反向边加上流量k
return k;
}
}
}
level[u]=-1;
return 0;
}
Dinic
int dinic()
{
int s=0,f;
while(bfs()) //若找到增广路
{
while((f=dfs(Start,0x3f3f3f3f))>0) s+=f; //增广并返回增广的流量
}
return s;
}