最大流,最小费用最大流:解析 + 各种板子

article/2025/9/28 19:22:02

网络流初步 + Edmond-Karp算法

网络流的基本概念

  • 源点,这个点只有流量的流出,没有流入。
  • 汇点,这个点只有流量的流入,没有流出。
  • 容量,每条有向边的最大可承受的流的理论大小。
  • 流量,每条有向边的最大可承受的流的实际大小。
  • 最大流,从源点可流入汇点的最大流量。

Edmond-Karp算法

1、如果可以找到增广的路径,取这条路径上的最小的容量作为当前的可增广的流量。

2、在这条增广的路径中的每一个有向边减去当前可增广的流量,同时在其反向边加上当前可增广的流量。

3、重复1的操作,如果不能找到可增广的路径,则说明,已经找到了最大流,输出答案即可。

为什么要在反向边上增加上当前可增广的流量。

毫无疑问这张图的最大流是 4 = 2 ( 1 − > 3 − > 4 ) + 2 ( 1 − > 2 − > 4 ) 4 = 2(1 -> 3 -> 4) + 2(1 -> 2 -> 4) 4=2(1>3>4)+2(1>2>4)

但是如果我们找寻的一条增广路径是 2 ( 1 − > 2 − > 3 − > 4 ) 2(1 -> 2 -> 3 -> 4) 2(1>2>3>4)之后,我们再也就找不到其他的增广路径了

但是如果我们在每一次取用这条边之后,在其反方向增加对应的反向边。

显然我们可以得到另一个增广路径 2 ( 1 − > 3 − > 2 − > 4 ) 2(1 -> 3 -> 2 -> 4) 2(1>3>2>4),这里我们得到的最大流,也是正确答案。

板子 + 例题

Flow Problem 题目链接

#include <bits/stdc++.h>using namespace std;const int INF = 0x3f3f3f3f;int maze[20][20], n, m;
int visit[20], pre[20];bool bfs(int st, int ed) {queue<int> q;memset(visit, 0, sizeof visit);q.push(st);visit[st] = 1;while(!q.empty()) {int temp = q.front();q.pop();if(temp == ed)  return true;for(int i = 1; i <= n; i++) {if(!visit[i] && maze[temp][i] > 0) {visit[i] = 1;q.push(i);pre[i] = temp;}}}return false;
}int max_flow(int st, int ed) {int ans = 0;while(bfs(st, ed)) {int now_max = INF;int p = ed;while(p != st) {now_max = min(now_max, maze[pre[p]][p]);p = pre[p];}p = ed;while(p != st) {maze[pre[p]][p] -= now_max;maze[p][pre[p]] += now_max;p = pre[p];}ans += now_max;}// cout << ans << endl;return ans;
}int main() {// freopen("in.txt", "r", stdin);int t, x, y, w;scanf("%d", &t);for(int cas = 1; cas <= t; cas++) {scanf("%d %d", &n, &m);memset(maze, 0, sizeof maze);for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);maze[x][y] += w;}printf("Case %d: %d\n", cas, max_flow(1, n));}return 0;
}

最大流

Edmond-Karp

原版的是用邻接矩阵写的,太耗内存了,这里改成邻接表。

#include <bits/stdc++.h>using namespace std;const int N1 = 1e4 + 10, N2 = 2e5 + 10;
const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], cnt;
int flow[N1], pre[N1], id[N1], n, m, s, t;void add(int x, int y, int w) {to[cnt] = y;nex[cnt] = head[x];cap[cnt] = w;head[x] = cnt++;
}void input() {scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, w;for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);add(x, y, w);add(y, x, 0);}
}void init() {memset(head, -1, sizeof head);cnt = 0;
}int max_flow() {int ans = 0;for(;;) {queue<int> q;memset(flow, 0, sizeof flow);flow[s] = INF;q.push(s);while(!q.empty()) {int temp = q.front();q.pop();for(int i = head[temp]; ~i; i = nex[i]) {if(!flow[to[i]] && cap[i] > 0) {flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;q.push(to[i]);}}if(flow[t]) break;}if(!flow[t])    break;int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}ans += flow[t];}return ans;
}int main() {// freopen("in.txt", "r", stdin);init();input();printf("%d\n", max_flow());return 0;
}

Dinic

玄学的Dinic

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N1 = 1e4 + 10, N2 = 2e5 + 10;
const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], cnt;
int now[N1];int dis[N1], n, m, s, t;void init() {memset(head, -1, sizeof head);cnt = 0;
}void add(int x, int y, int w) {to[cnt] = y;nex[cnt] = head[x];cap[cnt] = w;head[x] = cnt++;
}bool bfs() {memset(dis, -1, sizeof dis);queue<int> q;q.push(s);dis[s] = 0;now[s] = head[s];while(!q.empty()) {int temp = q.front();q.pop();if(temp == t)   return true;for(int i = head[temp]; ~i; i = nex[i]) {if(dis[to[i]] == -1 && cap[i]) {now[to[i]] = head[to[i]];dis[to[i]] = dis[temp] + 1;q.push(to[i]);}}}return false;
}ll dfs(int rt, ll f) {if(rt == t) return f;ll delta = f;for(int i = now[rt]; ~i; i = nex[i]) {now[rt] = i;if(dis[to[i]] == dis[rt] + 1) {int temp = dfs(to[i], min(delta, 1ll * cap[i]));cap[i] -= temp;cap[i ^ 1] += temp;delta -= temp;}if(delta == 0)  break;} return f - delta;
}ll Dinic() {ll ans = 0;while(bfs()) ans += dfs(s, 0x3f3f3f3f3f3f3f3f);return ans;
}int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, w;for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);add(x, y, w);add(y, x, 0);}printf("%lld\n", Dinic());return 0;
}

最小费用最大流

SPFA

#include <bits/stdc++.h>using namespace std;const int N1 = 5e3 + 10, N2 = 1e5 + 10;
const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], value[N2], cnt;int dis[N1], pre[N1], id[N1], flow[N1], visit[N1], n, m, s, t;void add(int x, int y, int f, int w) {to[cnt] = y;nex[cnt] = head[x];value[cnt] = w;cap[cnt] = f;head[x] = cnt++;
}bool spfa() {memset(visit, 0, sizeof visit);memset(dis, 0x3f, sizeof dis);queue<int> q;q.push(s);dis[s] = 0, visit[s] = 1, flow[s] = INF, pre[t] = -1;while(!q.empty()) {int temp = q.front();q.pop();visit[temp] = 0;for(int i = head[temp]; ~i; i = nex[i]) {if(cap[i] > 0 && dis[to[i]] > dis[temp] + value[i]) {dis[to[i]] = dis[temp] + value[i];flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;if(!visit[to[i]]) {q.push(to[i]);visit[to[i]] = 1;}}}}return  pre[t] != -1;
}int min_cost_and_max_flow() {int max_flow = 0, min_cost = 0;while(spfa()) {max_flow += flow[t];min_cost += flow[t] * dis[t];int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost);
}void init() {memset(head, -1, sizeof head);cnt = 0;
}int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);add(y, x, 0, -w);}min_cost_and_max_flow();return 0;
}

两个假的Dijkstra

洛谷模板题卡爆DIjkstra。

好像第一个稍优一点。

第一个假的Dijkstra

#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define x first
#define y secondusing namespace std;typedef pair<int, int> PII;
const int N1 = 5e3 + 10;
const int INF = 0x3f3f3f3f;int dis[N1], h[N1], flow[N1], pre[N1], id[N1], visit[N1], n, m, s, t;struct Edge {int to, cap, value, rever;Edge(int _to, int _cap, int _value, int _rever) : to(_to), cap(_cap), value(_value), rever(_rever) {}
};vector<Edge> G[N1];void add(int x, int y, int f, int w) {Edge temp1 = Edge(y, f, w, G[y].size());Edge temp2 = Edge(x, 0, -w, G[x].size());G[x].pb(temp1);G[y].pb(temp2);
}int min_cost_and_max_flow() {int min_cost = 0, max_flow = 0;memset(dis, 0x3f, sizeof dis);for(;;) {priority_queue<PII, vector<PII>, greater<PII> > q;dis[s] = 0, flow[s] = INF;q.push(mp(0, s));while(!q.empty()) {PII temp = q.top();q.pop();if(visit[temp.y])   continue;visit[temp.y] = 1;int u = temp.y;for(int i = 0; i < G[u].size(); i++) {Edge v = G[u][i];if(v.cap > 0 && dis[v.to] > dis[u] + v.value + h[u] - h[v.to]) {dis[v.to] = dis[u] + v.value + h[u] - h[v.to];flow[v.to] = min(v.cap, flow[u]);pre[v.to] = u;id[v.to] = i;q.push(mp(dis[v.to], v.to));}}}if(visit[t] == 0)    break;max_flow += flow[t];for(int i = 1; i <= n; i++) {h[i] += dis[i];dis[i] = INF;visit[i] = 0;}min_cost += flow[t] * h[t];int p = t;while(p != s) {G[pre[p]][id[p]].cap -= flow[t];G[p][ G[pre[p]][id[p]].rever].cap += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost);
}int main() {// freopen("in.txt", "r", stdin);scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);}min_cost_and_max_flow();return 0;
}

第二个假的Dijkstra

#include <bits/stdc++.h>
#define mp make_pairusing namespace std;typedef pair<int, int> PII;
const int N1 = 5e3 + 10, N2 = 1e5 + 10;
const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], value[N2], cnt;int visit[N1], flow[N1], dis[N1], pre[N1], id[N1], h[N1], n, m, s, t;void init() {memset(head, -1, sizeof head);cnt = 0;
}void add(int x, int y, int f, int w) {to[cnt] = y;nex[cnt] = head[x];value[cnt] = w;cap[cnt] = f;head[x] = cnt++;
}int min_cost_and_max_flow() {int min_cost = 0, max_flow = 0;memset(dis, 0x3f, sizeof dis);for(;;) {priority_queue<PII, vector<PII>, greater<PII> > q;q.push(mp(0, s));flow[s] = INF, dis[s] = 0;while(!q.empty()) {int temp = q.top().second;q.pop();// if(temp == t)   break;if(visit[temp]) continue;visit[temp] = 1;// if(temp == t)   break;for(int i = head[temp]; ~i; i = nex[i]) {if(cap[i] > 0 && dis[to[i]] > dis[temp] + value[i] + h[temp] - h[to[i]]) {dis[to[i]] = dis[temp] + value[i] + h[temp] - h[to[i]];flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;q.push(mp(dis[to[i]], to[i]));}}}if(visit[t] == 0)   break;for(int i = 1; i < n; i++) {h[i] += dis[i];visit[i] = 0;dis[i] = INF;}max_flow += flow[t];min_cost += flow[t] * h[t];int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost);  
}int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);add(y, x, 0, -w);}min_cost_and_max_flow();return 0;
}

http://chatgpt.dhexx.cn/article/wbALrwPf.shtml

相关文章

分配问题(最小费用最大流)

题目&#xff1a;有 n 件工作要分配给 n 个人做。第 i个人做第 j件工作产生的效益为 。试设计一个将 n件工作分配给 n个人做的分配方案&#xff0c;使产生的总效益最大。 分析&#xff1a;这是一道多解法问题&#xff0c;可以用带剪枝的搜索和图论的最小费用最大流的方法来做&…

最小费用最大流算法 网络流

最小费用最大流算法 图片来源 《趣学算法》 人民邮电出版社 陈小玉 代码实现 /* 参考:《趣学算法》陈小玉 人民邮电出版社 最小费用最大流---最小费用路算法 问题分析:在实际应用中&#xff0c;要同时考虑流量和费用&#xff0c;每条边除了给定容量之外&#xff0c;还定义了一…

网络流----最小费用最大流(EK+SPFA)

先来介绍一下什么是费用流&#xff08;部分内容参考bilibili董晓算法&#xff09; 给定一个网络G&#xff08;V&#xff0c;E&#xff09;&#xff0c;每条边有容量限制w(u,v)&#xff0c;还有单位流量的费用c(u,v)。 当&#xff08;u,v&#xff09;的流量为f(u,v)时&#xf…

【图论】网络流——最大流和最小费用流

【图论】网络流——最大流和最小费用流 文章目录 【图论】网络流——最大流和最小费用流1. 最大流问题1.1 基本概念1.2 寻求最大流的算法&#xff08;Ford-Fulerson&#xff09;1.3 matlab求最大流 2. 最小流问题2.1 基本概念2.2 求最小流的迭代算法2.3 matlab 求最大费用最小流…

网络流(2)-----最小费用最大流(附带讲解SPFA算法)

一.最小费用最大流&#xff08;简称费用流&#xff09;概念 1.什么是费用流问题 上篇文章我们讲解了最大流问题&#xff0c;那什么是最小费用最大流呢&#xff1f;听名字就可以看出&#xff0c;我们要在满足最大流的同时找到达成最大流的最小费用。对于一个网络流&#xff0c…

最小费用最大流问题详解

最小费用最大流问题 一、问题描述 在网络中求一个最大流f&#xff0c;使流的总输送费用最小。 b ( f ) ∑ ( v i , v j ) b i j f i j b(f) \sum\limits_{(v_i,v_j)} b_{ij} f_{ij} b(f)(vi​,vj​)∑​bij​fij​ ) &#xff08; b i j b_{ij} bij​ 表示弧 ( v i , v j…

最小费用最大流问题与算法实现(Bellman-Ford、SPFA、Dijkstra)

摘要 今日&#xff0c;对最小费用最大流问题进行了一个简单的研究&#xff0c;并针对网上的一些已有算法进行了查找和研究。博客和资料很多&#xff0c;但是留下的算法很多运行失败、出错&#xff0c;或者意义不明。这里&#xff0c;个人对其中的Bellman-Ford、SPFA、改进的Di…

如何区分冲突域和广播域?

举个例子&#xff0c;原始社会的人都生活在山洞里&#xff0c;每个人都住在自己的山洞里&#xff0c;洞穴的中间只有一个狭长的走廊可以出去&#xff0c;平时出去玩&#xff0c;大哥都会喊一嗓子&#xff0c;有人出去打猎不&#xff0c;所有人都听得到&#xff0c;这就是一个广…

冲突域和广播域区别

一、区别 1、广播域就是说如果站点发出一个广播信号后能接收到这个信号的范围。通常来说一个局域网就是一个广播域。冲突域指一个站点向另一个站点发出信号。除目的站点外&#xff0c;有多少站点能收到这个信号。这些站点就构成一个冲突域。 2、冲突域通过集线器连接&#xf…

冲突域和广播域区别,集线器、交换机和路由器对比

冲突域 我们把以太网想象为对讲机&#xff0c;电脑想象为使用对讲机的人&#xff0c;数据传输想象为使用对讲机说话。现在一群人打真人CS&#xff0c;两个及以上的人同时通过对讲机说话&#xff0c;就听不清在说什么了&#xff0c;这就是冲突。对讲机通道只能一人单独使用。对…

冲突域和广播域; 集线器、交换机以及路由器比较

转自https://blog.csdn.net/gui951753/article/details/79402528#1%E5%B7%A5%E4%BD%9C%E5%B1%82%E6%AC%A1%E4%B8%8D%E5%90%8C 目录 冲突域和广播域 联网中继设备 集线器&#xff08;hub&#xff09; 交换机(switch) 路由器(route) 三者的异同 冲突域和广播域 在介绍这三…

交换机基础原理,冲突域和广播域

交换机的基本定义 提供了大量的接入端口&#xff0c;能够很好的满足大量用户接入到网络中的需求。 在OSI模型的二层&#xff0c;数据链路层&#xff1b; 可以识别数据包中的MAC地址信息&#xff0c;根据MAC地址进行转发数据&#xff0c;并且会将这些MAC地址与对应的端口记录在…

冲突域和广播域的区分

一、概念理解&#xff1a; 1、冲突域&#xff08;物理分段&#xff09;&#xff1a; 连接在同一导线上的所有工作站的集合&#xff0c;或者说是同一物理网段上所有节点的集合或以太网上竞争同一带宽的节点集合。这个域代表了冲突在其中发生并传播的区域&#xff0c;这个区域可…

冲突域和广播域的区别

冲突域 冲突域指的是会产生冲突的最小范围&#xff0c;在计算机和计算机通过设备互联时&#xff0c;会建立一条通道&#xff0c;如果这条通道只允许瞬间一个数据报文通过&#xff0c;那么在同时如果有两个或更多的数据报文想从这里通过时就会出现冲突了。 冲突域的大小可以衡…

冲突域和广播域

冲突域&#xff1a; 冲突域是信道的争抢&#xff0c;信道只有一条&#xff0c;A在使用&#xff0c;B就不可以使用&#xff0c;这样就会产生冲突&#xff0c;这就是冲突域的产生 在一个信道上的所有主机组成一个冲突域&#xff0c;划分网络越小越好&#xff0c;不会引起很大的冲…

如何理解冲突域和广播域?(转)

如何理解冲突域和广播域&#xff1f;&#xff08;转&#xff09; 转自&#xff1a;http://blog.sina.com.cn/s/blog_7e8dec240102wyio.html 网上看到的好文章&#xff0c;整理下来&#xff0c;方便复习&#xff0c;侵删 1、冲突域&#xff1a; 【定义】在同一个冲突域中的每…

设备划分冲突域和广播域

冲突域是一种物理分段&#xff0c;指连接到同一导线上所有工作站的集合、同一物理网段上所有节点的集合或是以太网上竞争同一带宽节点的集合。冲突域表示冲突发生并传播的区域&#xff0c;这个区域可以被认为是共享段。在OSI模型中&#xff0c;冲突域被看作是OSI第一层的概念&a…

HCIA—冲突域与广播域(详解 + 区别)

目录 一、冲突域&#xff1a; &#xff08;1&#xff09;HUB组网&#xff1a; &#xff08;2&#xff09;冲突域 概述 特点&#xff1a; 二、广播域&#xff1a; &#xff08;1&#xff09;广播域 概述特点&#xff1a; 三、冲突域 与 广播域的区别与联系&#xff1a; 一…

网络基础之冲突域和广播域

温故&#xff1a; 前面的几天 &#xff0c;主要讲了OSI网络七层的相关知识&#xff0c;着重的分析了每一层所具备的功能和服务&#xff0c;在这里我再次强调一遍&#xff1a;功能指的是本层的作用&#xff0c;服务指的是本层能为上层提供的业务&#xff0c;至于协议则是定义了每…

广播域和冲突域

在准备软考的时候将广播域看成了广域网,结果就错了一道题,这篇文章就从这道错题开始... 1.广播域和冲突域的定义 广播域:网络中能接受任一设备发出的广播帧的设备的集合. 冲突域:在同一个网络内,如果任意两台计算机在同时通信是会发生冲突,那么它们所组成的网络就是一个冲突域…