算法设计与分析 第五次编程作业 1571. 最大流

news/2024/11/2 14:17:03/

题目描述

给出一个网络图,及其源点汇点,求出其网络最大流。

输入格式

第一行包含四个正整数 n , m , s , t n,m,s,t n,m,s,t, 分别表示点的个数,有向边的数量,源点序号,汇点序号。

接下来 m m m行每行三个正整数, u i , v i , w i u_i,v_i,w_i ui,vi,wi,表示第 i i i条有向边从 u i u_i ui出发,到达 v i v_i vi,能通过的最大流量为 w i w_i wi

输出格式

一个正整数,即为该网络的最大流。

样例输入

4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40

样例输出

50

数据范围

对于 30% 的数据,保证 n ≤ 10 n \le 10 n10 m ≤ 25 m\le 25 m25

对于 100% 的数据,保证 1 ≤ n ≤ 100 1\le n\le 100 1n100 1 ≤ m ≤ 1000 1\le m\le 1000 1m1000 0 ≤ w < 2 31 0≤w<2^{31} 0w<231

时空磁盘限制(运行时)

时间限制: 1000 ms
空间限制: 244 MiB

解决方案

//modified from v3
//https://www.geeksforgeeks.org/ford-fulkerson-algorithm-for-maximum-flow-problem/
#include <iostream>
#include <limits.h>
#include <queue>
#include <string.h>
using namespace std;#define V 101
long long int graph[V][V];//因为节点数较小,使用邻接矩阵存图bool bfs(long long int rGraph[V][V], int n, int s, int t, int parent[])
{bool visited[V];memset(visited, 0, sizeof(visited));queue<int> q;q.push(s);visited[s] = true;parent[s] = -1;while (!q.empty()) {int u = q.front();q.pop();for (int v = 1; v <= n; v++) {if (visited[v] == false && rGraph[u][v] > 0) {//此时找到了一个可以更新距离信息的节点if (v == t) {//如果v等于汇,那么说明存在一条s到t的路径,这条路径被parent数组记录下来了。只需返回即可。parent[v] = u;return true;}q.push(v);parent[v] = u;visited[v] = true;}}}return false;//没有到汇的路径,返回false
}long long int EK(long long int graph[V][V], int n, int s, int t)
{int u, v;long long int rGraph[V][V]; // Residual graphfor (u = 0; u < V; u++)for (v = 0; v < V; v++)rGraph[u][v] = graph[u][v];int parent[V]; //用于指代节点的访问顺序long long int max_flow = 0; while (bfs(rGraph, n,  s, t, parent)) {long long int path_flow = LONG_MAX;//这里直接调用limits库的LONG_MAXfor (v = t; v != s; v = parent[v]) {//找到这条路径上最小的容量u = parent[v];path_flow = min(path_flow, rGraph[u][v]);}for (v = t; v != s; v = parent[v]) {u = parent[v];rGraph[u][v] -= path_flow;rGraph[v][u] += path_flow;}max_flow += path_flow;}return max_flow;
}int main()
{int m, n, s, t;memset(graph,0,sizeof(graph));cin >> n >> m >> s >> t;int u, v, w;for (int i=0;i<m;++i) {cin >> u >> v >> w;graph[u][v] += w;}cout << EK(graph,n, s, t);return 0;
}

解决方案2

//modified from v4
//modified from v2
//https://www.geeksforgeeks.org/ford-fulkerson-algorithm-for-maximum-flow-problem/
#include <iostream>
#include <string.h>
#include <queue>
#include <limits.h>
using namespace std;const int MAXN = 101;
const int MAXM = 1001;
int m, n, s, t;
long long int edges[MAXN][MAXN]; //因为节点数较小,使用邻接矩阵存图。似乎不需要另外定义一个残差网络
int parent[MAXN]; //用于指代节点的访问顺序
bool visited[MAXN];//int min(int a, int b) {return (a > b ? b : a);}bool bfs()
{memset(visited,0,sizeof(visited));queue<int> q;q.push(s);visited[s] = true;parent[s] = -1;//接下来是BFSloopwhile (!q.empty()) {int u = q.front();q.pop();for (int v=1;v<=n;++v) {if (visited[v] == false && edges[u][v] > 0) {//此时找到了一个可以更新距离信息的节点if (v == t) {//如果v等于汇,那么说明存在一条s到t的路径,这条路径被parent数组记录下来了。只需返回即可。parent[v] = u;return true;}q.push(v);parent[v] = u;visited[v] = true;}}}return false; //没有到汇的路径,返回false
}long long int EK()
{long long int max_flow=0; //根据w的范围,此处需要long longint u, v;while (bfs()) {long long int path_flow = LONG_MAX;//由于w的上限是2^31-1,实在是太大了, 这里直接调用limits库的INT_MAXfor (v = t;v != s;v = parent[v]) { //找到这条路径上最小的容量u = parent[v];path_flow = min(path_flow,edges[u][v]);}for (v = t;v != s;v = parent[v]) {u = parent[v];//在之前漏了这行!!!!edges[u][v] -= path_flow;edges[v][u] += path_flow;}max_flow += path_flow;memset(parent,0,sizeof(parent));}return max_flow;
}int main()
{memset(edges,0,sizeof(edges));cin >> n >> m >> s >> t;int u, v, w;for (int i=0;i<m;++i) {cin >> u >> v >> w;edges[u][v] += w;}cout << EK();return 0;
}

总结

本题要求实现上课讲到的Edmond-Karp算法,参考了https://www.geeksforgeeks.org/ford-fulkerso
n-algorithm-for-maximum-flow-problem/。基本思路是:用邻接矩阵存图(因为 n n n较小),初始时设每条边的capacity为0,在运行Edmond-Karp算法时,重复调用bfs,用parent数组存储寻找到的path,更新残差网络(residual graph)。注意,本题很坑的一点是会有重边,所以在初始化存边的时候,需要用+=,并且两个图都要用long long int型的数组,否则第6第7数据点过不了(感谢rxygg指出这个问题)。

声明

题目来自校内OJ平台,本人没有题目的版权。如有侵权,请联系本人删除。


http://www.ppmy.cn/news/686198.html

相关文章

东北大学OJ-1571: 实验5-13:分段函数(多分支)

东北大学OJ-1571: 实验5-13:分段函数(多分支) 大家好,我叫亓官劼(q guān ji ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博客地址为:亓官劼的博客,B站昵称为:亓官劼,地址为亓官劼的B站 本文原创为亓官劼,请大家支持原创,部分平台一直在盗取博主的文…

有哪些工具或者软件堪称神器?

著作权归作者所有。 商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 作者&#xff1a;居里安同学 链接&#xff1a;http://www.zhihu.com/question/36546814/answer/70322446 来源&#xff1a;知乎 直接搬运我在另一个问题的答案了&#xff1a;有哪些工具或者软…

markdown基本语法 【未修改完成!】

目录 Markdown 简介Markdown 编辑器推荐 在线版 1. dillinger2. StackEdit3. MaHua4. 简书5. 马克飞象windows 1. MarkdownPad2. MarkPad3. Smark4. MiuOSX 1. Mou2. MacDown3. Ulysses4. iA Writer5. MWeb跨平台 1. Cmd Markdown2. 小书匠编辑器3. FarBox4. Sublime Text 25. …

【Linux入门学习之】Ubuntu常用软件

【Linux入门学习之】Ubuntu常用软件 速配指南之软件参考 本文定位&#xff1a;作为速配指南的补充&#xff0c;列出国内用户比较常用的软件。请将论坛软件推荐版块的内容逐步转移至wiki&#xff0c;而非本文。 本文作用&#xff1a;为新手指明软件的方向&#xff0c;也可供已…

Android手机开发总结

导读&#xff1a;对于Android开发者来说&#xff0c;成系列的技术文章对他们的技术成长帮助最大。如下是我们向您强烈推荐的主题为Android开发的第一个系列文章。 《Android核心分析》整理如下&#xff1a; 1. 方法论探讨之设计意图 为什么要研究Android&#xff0c;是因为它…

Linux下的经典软件

转自&#xff1a;http://blog.csdn.net/real_myth/article/details/56012539 Linux下的经典软件(史上最全) Linux下的经典软件(史上最全) 前言 从2012年接触Linux系统以来就被Linux系统所吸引&#xff0c;2个月后便完全抛弃了Windows。在这2年的时间里&#xff0c;我尝试了很多…

堪称「神器」的电脑软件

1.Raindrop.io&#xff1a;这个我自己试用了一个多月之后才来跟各位报告——它真的太好用啦&#xff01;这是一个在线书签&#xff08;我就是这么喜欢这种东西……&#xff09;各种浏览器插件一个不少&#xff0c;书签分组和打标签功能一应俱全&#xff0c;手机客户端也很棒&am…

Linux下的经典软件(史上最全)

Linux下的经典软件(史上最全) Linux下的经典软件(史上最全) 前言 从2012年接触Linux系统以来就被Linux系统所吸引&#xff0c;2个月后便完全抛弃了Windows。在这2年的时间里&#xff0c;我尝试了很多Linux发行版: Gentoo, Fedora, Ubuntu, Debian等。在这些系统中又尝试了很多种…