专栏文章
题解:P3376 【模板】网络最大流
P3376题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipj3re6
- 此快照首次捕获于
- 2025/12/03 12:50 3 个月前
- 此快照最后确认于
- 2025/12/03 12:50 3 个月前
P3376 【模板】网络最大流
最大流算法:
引入:可以理解为有一个自来水厂要运水,每个管道最大通过的流量为 。
实现:可以通过 BFS 找一条新路线直到没得找了,每次找到新路线计算最大流。
容量约束:因为通过的流量不能大于 所以当前路径的最大流不能大于当前路径里最小的边权。
反悔:为了解决错误的路径选择,所以允许流量回流,允许返回。
核心逻辑:通过不断寻找并利用增广路径来逐步增加总流量,直到无法找到新的增广路径为止。
题目概述
题目大意:计算从点 到点 的最大流。
算法思路:
残留网络:通过维护一个容量矩阵 ,记录每条边的剩余容量。
路径:每次用 bfs 寻找一条从源点到汇点的路径,且每条路径上都有剩余的容量。
流量更新:计算路径上的最小容量 ,沿着正向边减去 ,再沿着反向边增加 ,因为允许反悔也就是流量回流。
结束条件:当没有办法找到其他的增广路线时,当前累计的流量为最大流。
代码解析:
BFS部分:
CPPll bfs(ll s, ll t) {
memset(pre, -1, sizeof(pre));
memset(vis, 0, sizeof(vis));
queue<int> q;
vis[s] = 1;
q.push(s);
while (!q.empty()) {
int now = q.front();
q.pop();
for (int i = 1; i <= n; i++) {
if (!vis[i] && cap[now][i] > 0) {
vis[i] = 1;
pre[i] = now; // 记录前驱节点
if (i == t) return 1;
q.push(i);
}
}
}
return 0;
}
功能:通过 BFS 找一条从 到 的路径。
计算最大流:
CPPll wll(ll s, ll t) {
ll v, u, d, mfw = 0;
while (bfs(s, t)) { // 循环寻找增广路径
v = t;
d = 1e8;
while (v != s) { // 计算路径最小剩余容量
u = pre[v];
d = min(d, cap[u][v]);
v = u;
}
mfw += d;
v = t;
while (v != s) { // 更新残留网络
u = pre[v];
cap[u][v] -= d;
cap[v][u] += d;// 处理反向边
v = u;
}
}
return mfw;
}
功能:累加每条路径的流量,更新残余流量。
整体代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n, m, x, t; // n:节点数 m:边数 x:源点 t:汇点
ll a, b, c; // 临时变量用于输入边信息
ll cap[5010][5010]; // cap[u][v]表示u->v的剩余容量
ll pre[100000]; // 用于BFS找增广路径
ll vis[100000]; // 防止重复访问
ll bfs(ll s, ll t) {
memset(pre, -1, sizeof(pre)); // 初始化为-1
memset(vis, 0, sizeof(vis));
queue<int> q;
vis[s] = 1; // 标记源点已访问
q.push(s);
while (!q.empty()) {
int now = q.front();
q.pop();
// 遍历所有可能的邻接点
for (int i = 1; i <= n; i++) {
// 存在剩余容量且未访问过
if (!vis[i] && cap[now][i] > 0) {
vis[i] = 1;
pre[i] = now; // 记录前驱节点
if (i == t) return 1; // 找到汇点,立即返回
q.push(i);
}
}
}
return 0; // 未找到增广路径
}
ll wll(ll s, ll t) {
ll v, u, d, mfw = 0; // 最大流累计值
// 每次寻找一条增广路径
while (bfs(s, t)) {
v = t;
d = 100000000; // 初始化为极大值
// 回溯路径找最小剩余容量
while (v != s) {
u = pre[v];
d = min(d, cap[u][v]); // 找路径上的瓶颈容量
v = u;
}
mfw += d; // 累计到总流量
// 更新残留网络
v = t;
while (v != s) {
u = pre[v];
cap[u][v] -= d; // 减少正向边容量
cap[v][u] += d; // 增加反向边容量(允许回流)
v = u;
}
}
return mfw;
}
signed main() {
std::ios::sync_with_stdio(false);
cout.tie(0); cin.tie(0);
cin >> n >> m >> x >> t;
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
cap[a][b] += c; // 处理重边:直接累加容量
}
ll al = wll(x, t);
cout << al;
return 0;
}
谢谢观看
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...