函数:
邻接表部分:
const int INF = 0x3f3f3f3f, maxn = 157;
int N, NP, NC, M;
struct E {
int u, v, flow;
E(int u = 0, int v = 0, int flow = 0): u(u), v(v), flow(flow) {}
} edg[maxn * maxn];
int cnt_edg, S, T;
vector<int> edge[maxn]; // 边集
int dis[maxn];//距源点距离,分层图
int current[maxn];//当前弧
void addedg(int u, int v, int flow) {
edge[u].push_back(cnt_edg);
edg[cnt_edg++] = E(u, v, flow); // 正向边
edge[v].push_back(cnt_edg);
edg[cnt_edg++] = E(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
BFS建立分层图:
bool bfs() {
queue<int> q;
q.push(S);
memset(dis, -1, sizeof(dis));
dis[S] = 0;
while (!q.empty()) {
int index = q.front();
q.pop();
int sz = int(edge[index].size());
for (int i = 0; i < sz; i++) {
E &e = edg[edge[index][i]];
if (e.flow > 0) {
if (dis[e.v] < 0) {
dis[e.v] = dis[index] + 1;
q.push(e.v);
}
}
}
}
return bool(~dis[T]); // 返回是否能够到达汇点
}
DFS增广 & 当前弧优化:
int dfs(int index, int maxflow) {
if (index == T)
return maxflow;
// i = current[index] 当前弧优化
int sz = int(edge[index].size());
for (int i = current[index], number; number = edge[index][i], i < sz; i++) {
current[index] = i;
E &e = edg[number];
if (dis[e.v] == dis[index] + 1 && e.flow > 0) {
int flow = dfs(e.v, min(maxflow, e.flow));
if (flow != 0) {
e.flow -= flow; // 正向边流量降低
edg[number ^ 1].flow += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
Dinic运算主体:
int dinic() {
int ans = 0;
while (bfs()) {// 建立分层图
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (bool(flow = dfs(S, INF))) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}
其它:
其实当前弧优化就只是在增广的过程中添加一个current[]数组记录下一次该走的边以避免重复,虽然是个很细微的部分但是在实际遍历当中的优化是十分巨大的。
然后就是在每次分层完之后记得对current[]进行初始化。
汇总:
const int INF = 0x3f3f3f3f, maxn = 157;
int N, NP, NC, M;
struct E {
int u, v, flow;
E(int u = 0, int v = 0, int flow = 0): u(u), v(v), flow(flow) {}
} edg[maxn * maxn];
int cnt_edg, S, T;
vector<int> edge[maxn]; // 边集
int dis[maxn];//距源点距离,分层图
int current[maxn];//当前弧
void addedg(int u, int v, int flow) {
edge[u].push_back(cnt_edg);
edg[cnt_edg++] = E(u, v, flow); // 正向边
edge[v].push_back(cnt_edg);
edg[cnt_edg++] = E(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
bool bfs() {
queue<int> q;
q.push(S);
memset(dis, -1, sizeof(dis));
dis[S] = 0;
while (!q.empty()) {
int index = q.front();
q.pop();
int sz = int(edge[index].size());
for (int i = 0; i < sz; i++) {
E &e = edg[edge[index][i]];
if (e.flow > 0) {
if (dis[e.v] < 0) {
dis[e.v] = dis[index] + 1;
q.push(e.v);
}
}
}
}
return bool(~dis[T]); // 返回是否能够到达汇点
}
int dfs(int index, int maxflow) {
if (index == T)
return maxflow;
// i = current[index] 当前弧优化
int sz = int(edge[index].size());
for (int i = current[index], number; number = edge[index][i], i < sz; i++) {
current[index] = i;
E &e = edg[number];
if (dis[e.v] == dis[index] + 1 && e.flow > 0) {
int flow = dfs(e.v, min(maxflow, e.flow));
if (flow != 0) {
e.flow -= flow; // 正向边流量降低
edg[number ^ 1].flow += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int dinic() {
int ans = 0;
while (bfs()) {// 建立分层图
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (bool(flow = dfs(S, INF))) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}