题解:洛谷 P3376 【模板】网络最大流
【题目来源】
【题目描述】
如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
【输入】
第一行包含四个正整数 \(n,m,s,t\),分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来 \(m\) 行每行包含三个正整数 \(u_i,v_i,w_i\),表示第 \(i\) 条有向边从 \(u_i\) 出发,到达 \(v_i\),边权为 \(w_i\)(即该边最大流量为 \(w_i\))。
【输出】
一行,包含一个正整数,即为该网络的最大流。
【输入样例】
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 30
【输出样例】
50
【算法标签】
《洛谷 P3376 网络最大流》 #网络流# #模板题# #O2优化#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 205, M = 5005 * 2;
int n, m, s, t; // 点数,边数,源点,汇点
// 使用数组模拟邻接表
int h[N], e[M], w[M], ne[M], idx = 2; // idx从2开始,方便找反向边
int d[N], cur[N]; // d: 层次深度,cur: 当前弧优化数组
// 添加有向边和反向边
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// BFS构建层次图
bool bfs()
{
memset(d, 0, sizeof(d));
queue<int> q;
q.push(s);
d[s] = 1;
while (q.size())
{
int u = q.front();
q.pop();
for (int i = h[u]; i != -1; i = ne[i])
{
int v = e[i];
if (d[v] == 0 && w[i]) // 如果v未访问且边有容量
{
d[v] = d[u] + 1;
q.push(v);
if (v == t)
{
return true; // 找到汇点
}
}
}
}
return false; // 无法到达汇点
}
// DFS进行多路增广
int dfs(int u, int mf)
{
if (u == t)
{
return mf; // 到达汇点
}
int sum = 0;
for (int i = cur[u]; i != -1; i = ne[i])
{
cur[u] = i; // 当前弧优化
int v = e[i];
if (d[v] == d[u] + 1 && w[i]) // 满足层次关系和容量限制
{
int f = dfs(v, min(mf, w[i]));
w[i] -= f; // 正向边减少容量
w[i ^ 1] += f; // 反向边增加容量
sum += f;
mf -= f;
if (mf == 0)
{
break; // 流量已用完
}
}
}
if (sum == 0)
{
d[u] = 0; // 残量网络中u不可达
}
return sum;
}
// Dinic算法主函数
int dinic()
{
int flow = 0;
while (bfs()) // 每次BFS构建新的层次图
{
memcpy(cur, h, sizeof(h)); // 重置当前弧
flow += dfs(s, 1e9); // 从源点开始增广
}
return flow;
}
signed main()
{
cin >> n >> m >> s >> t;
memset(h, -1, sizeof(h));
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w), add(v, u, 0); // 添加正向边和反向边
}
cout << dinic() << endl;
return 0;
}
【运行结果】
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 30
50
浙公网安备 33010602011771号