// Dinic算法.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <queue>
#include <string.h>
#define MAXN 205
#define MAXM 5005
#define INF 0x3f3f3f3f
typedef long long ll;
ll cnt = -1;
//点u深度
ll depth[MAXN];
//cur[u]记录了已经搜索到第几条以u为起点的边,并且从该边开始求增广路径
//因为当前边之前的边通往汇点的路的残量都已求得,无需再次求增广
//这样可以防止每次都从以u为起点的第一条边开始求增广路径
ll cur[MAXN];
//以u为起点的最后一条边
ll head[MAXN];
ll s, t; //源点,汇点
ll m, n; //n为顶点数,m为边数
using namespace std;
struct ArcType
{
ll to = -1;
ll w = 0;
ll next = -1;
}arc[MAXM << 1];//增添反边,因此边数乘2
void add(ll u, ll v, ll w)
{
cnt++;
arc[cnt].to = v;
arc[cnt].w = w;
arc[cnt].next = head[u];
head[u] = cnt;
}
void addArc(ll u, ll v, ll w)
{
add(u, v, w);
add(v, u, 0);
}
bool bfs()
{
queue<ll> que;
while (!que.empty())
que.pop();
memset(depth, -1, sizeof(depth));
depth[s] = 0;
que.push(s);
while (!que.empty())
{
ll u = que.front();
que.pop();
for (ll i = head[u]; ~i; i = arc[i].next)
{
if (!~depth[arc[i].to] && arc[i].w) //下一个点在下一层,而且这条边连通
{
depth[arc[i].to] = depth[u] + 1;
que.push(arc[i].to);
}
}
}
return ~depth[t]; //depth[t]!=-1
}
ll dfs(ll u, ll flow)
{
if (u == t)
return flow;
for (ll& i = cur[u]; ~i; i = arc[i].next)
{
if (depth[arc[i].to] == depth[u] + 1 && arc[i].w)
{
//一直dfs递归到汇点(递归出口 u==t)
//这样每次都求了flow(当前最小残量)和当前边的残量的最小值
//并把flow更新为该最小值
//最终出口得到的flow就是这条增广路径的残量
ll f = dfs(arc[i].to, min(flow, arc[i].w));
if (f)
{
arc[i].w -= f;
arc[i ^ 1].w += f;
return f; //返回这条增广路径的残量
}
}
}
return 0;
}
void createGraph()
{
cnt = -1;
memset(head, -1, sizeof(head));
cin >> n >> m >> s >> t;
ll u, v, w;
for (ll i = 0; i < m; i++)
{
cin >> u >> v >> w;
addArc(u, v, w);
}
}
ll dinic()
{
createGraph();
ll ans = 0;
//每次bfs都是为了给图分层
//多次bfs的原因是,分层后,dfs只能沿着深度递增的路径搜索
//当所有满足深度递增的路径都搜索完后,还有部分不满足深度递增的增广路径
//因此需要再次bfs,重新分层,这样就可以再次进行bfs求另一波增广
//这样一直bfs分层,直到无法分层,即从源点到汇点所有路径残量都为0(即s, t即不连通)
while (bfs())
{
//每次bfs之后要将cur[]数组初始化为head[]
//不然每个cur[u]存的是上次递归完后的边序号,会丢失很多结果
//这样很有可能使得无论怎样dfs不会有新的增广路径被找到,s, t始终是连通的
//导致bfs无限循环分层的结果
memcpy(cur, head, sizeof(head));
//每次dfs只能求得一条增广路径
//while循环不断求从源点到汇点的增广路径
//直到所有路径均不满足层数递增且残量>0,此时dfs返回0,while循环结束
while(int f = dfs(s, INF))
{
ans += f;
}
}
return ans;
}
int main()
{
cout << dinic() << endl;
}
/*
3 2 1 3
1 2 1
2 3 1
3 3 1 3
1 2 1
2 3 1
1 3 1
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
*/
Dinic算法之最简单易懂代码(配详细注释)
最新推荐文章于 2022-07-26 19:20:06 发布