dinic算法是一种求最大流的算法,与EK算法不同,dinic算法在求增长通路的时候,先BFS进行图的分层操作,在DFS寻找增长通路的时候,榨干一条路径上的所有流量。简单的说就是,一次分层,多次增长。
关于dinic算法的两个优化:
1.当前弧优化,在进行寻找增长通路的过程中,记录当前处理的边,做到下一次寻找增长通路的时候,不重复寻找;
2.在进行分层,如果在分层网络中找到汇点T,则停止进行分层,
定义使用的数据结构
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include "Queue.h"
#define MAXNUM 100*100 //最大边的个数
#define MAXVERTEX 100 //最大顶点的个数
#define INF 0x7ffff //设置初始流量为最大值
struct {
int to; //终点
int weight; //边的权值
int next; //同一顶点下一条边的位置
}edges[MAXNUM]; //edge[MAXNUM]为边集
int head[MAXVERTEX], tot; //head数组记录每个顶点开始的第一条边的位置,tot,记录边的个数
int N, M; //N为顶点个数,M为边数
int cur[MAXVERTEX]; //记录当前增长的边,做当前弧优化
int depth[MAXVERTEX]; //记录分层网络
加边函数
void addEdge(int v,int to,int weight) {
//加边函数
//加入一条从v到to权值为weight的边
edges[tot].to = to;
edges[tot].weight = weight;
edges[tot].next = head[v];
head[v] = tot++;
//加入一条反向边,初始化权值为0
edges[tot].to = v;
edges[tot].weight = 0;
edges[tot].next = head[to];
head[to] = tot++;
//注意正向边和反向边的关系为 正向边^1为反向边,反之亦然;
}
dinic算法
int BFS(int s,int t) { //构建分层网络
linkQueue Q;
Q = createQueue(); //创建队列
//depth数组初始化
memset(depth, 0, sizeof(int)*N); //depth数组记录分层的情况
EeueueQueue(s, Q);
depth[s] = 1; //源点的深度为1
while (!IsEmpty(Q)) {
int v = frontAndDeueue(Q); //出队列
for (int i = head[v]; ~i;i = edges[i].next) {
//访问与v点相连的所有边,判断是否能分层
if (edges[i].weight > 0 && depth[edges[i].to] == 0) {
//如果该边有流量,并未进行过分层,则可以进行分层
depth[edges[i].to] = depth[v] + 1;
if (i == t) //对dinic算法进行优化,如果在分层中找到汇点,则停止分层
return 1;
EeueueQueue(edges[i].to, Q); //入队列
}
}
}
disposeQueue(Q); //销毁队列
if (depth[t] == 0) //在分层过程中没有找到汇点,说明无增长通路
return 0;
else
return 1;
}
int DFS(int s,int t,int dist) {
//根据分层网络,寻找增长通路
//s为源点,t为汇点,dist为当前的流量
if (s == t) { //走到汇点t,则返回流量值大小
return dist;
}
for (int i = cur[s]; ~i;i = edges[i].next) {
cur[s] = i; //记录当前弧
if ((depth[edges[i].to] == depth[s] + 1) && edges[i].weight != 0) {
//是下一层网络,并且权值不为0,则允许向下层增长
int flow;
flow = edges[i].weight < dist ? edges[i].weight : dist;
//在一条通路上,能通过的最大流量,为最小边的流量
int d = DFS(edges[i].to, t, flow); //向下层搜索
if (d > 0) { //返回的流量大于0,则找到汇点,则进行路径上流量的更新
edges[i].weight -= d;
edges[i ^ 1].weight += d;
return d; //返回上一层
}
}
}
return 0;
}
//dinic算法函数入口
int dinic(int s,int t) {
int flow = 0; //记录最大流
while (BFS(s,t)) { //调用BFS做分层操作,一次分层,多次增长
//初始化cur数组,cur初始化为head数组
for (int i = 0; i < N;i++) {
cur[i] = head[i];
}
while (int d = DFS(s, t, INF)) { //DFS寻找增长通路,初始流量为无穷
//寻找增长通路
flow += d;
}
}
return flow;
}