网络流 练习
来源:互联网 发布:大学生借款软件 编辑:程序博客网 时间:2024/05/21 22:39
题目:利用Ford_Fulkerson (标号法)求图1(a)及2(a)所示的容量网络的最大流,输出各条弧及其流量,以及求得的最大流流量。
(1)
(2)
分析:
在下面的程序中,以邻接矩阵存储容量网络,但邻接矩阵中的元素为结构体ArcType类型变量。该结构体描述了网络中弧的结构,包含容量c和流量f两个成员。在程序中,还定义了三个数组:flag[n], prev[n], alpha[n],其中:
1) flag[n]表示顶点状态,其元素取值及含义为:-1-未标号,0-已标号未检查,1-已标号已检查;
2) prev[n]为标号的第一个分量:指明标号从哪个顶点得到,以便找出可改进量;
3) alpha[n]为标号的第二个分量:用以确定增广路的可改进量α。
另外,如前所述,从一个已标号未检查的顶点出发,对它的邻接顶点进行标号时,采用的是广度优先搜索的策略,因此,在程序中,定义了一个数组queue[n]来模拟队列;并定义了两个相关变量qs和qe,分别表示队列头位置和队列尾位置,约定从队列头取出结点,从队列尾插入结点;当qs<qe时表示队列非空。
每一次标号过程为:
(1) 先将flag、prev和alpha这3个数组各元素都初始化-1。
(2) 将源点初始化为已标号未检查顶点,即flag[0] = 0, prev[0] = 0, alpha[0] = INF,INF表示无穷大;并将源点入队列。
(3) 当队列非空并且汇点没有标号,从队列头取出队列头顶点,设这个顶点为v,v肯定是已标号未检查顶点;因此,检查顶点v的正向和反向“邻接”顶点,如果没有标号并当前可以进行标号,则对这些顶点进行标号并入队列,这些顶点都是已标号未检查顶点;此后顶点v为已标号已检查顶点。反复执行这一步直至队列为空或汇点已获得标号。
标号完毕后,要进行调整,调整方法是:从汇点出发,通过标号的第1个分量,即prev[5],采用“倒向追踪”方法,一直找到源点为止,这个过程途经的顶点和弧就构成了增广路。可改进量为汇点标号的第2个分量,即alpha[5]。
代码:
#include <iostream>#include <cstring>#include <cmath>#include <cstring>using namespace std;#define MIN(a, b) (a > b ? b : a)const int MAXN = 1000;const int INF = 10000000;struct ArcType//每个弧的容量以及弧的实际流量{ int c, f;};ArcType Edge[MAXN][MAXN];int flag[MAXN];//如果该顶点没有标号则为-1,如果已经访问,且没有检查其邻接顶点则标记为0,如果已经访问并且已经检查其邻接顶点则标记为1;int pre[MAXN];//pre[i]表示标号时,顶点i的前一个顶点,即第一个分量int alpha[MAXN];//标号时第二个分量int que[MAXN];//广搜时的队列int v;//队列头元素出队时,接收队头元素;int qs, qe;//qs类似队列对头指针,qe为队尾指针int i, j;int n, m;//图的顶点数,边数void Ford_Fulkerson(){ while(1) { memset(flag, 0xff, sizeof(flag)); memset(alpha, 0xff, sizeof(alpha)); memset(pre, 0xff, sizeof(pre)); flag[0] = 0;//源点标记已经访问而未检查,并且入队, pre[0] = 0;//一般都是把源点的前一个顶点设置为0,其第二个分量标记为无穷大,因为从源点可以流出任意多的流量 alpha[0] = INF; qs = qe = 0; que[qe++] = 0; while(qs < qe && flag[n-1] == -1)//如果汇点未被标记,则进行下去 { v = que[qs++]; for(i = 0; i < n; ++i)//检查v的邻接顶点 { if(flag[i] == -1)//顶点i未被访问 { if(Edge[v][i].c < INF && Edge[v][i].f < Edge[v][i].c) { pre[i] = v; flag[i] = 0; alpha[i] = MIN(alpha[v], Edge[v][i].c - Edge[v][i].f); que[qe++] = i; } else if( Edge[i][v].c < INF && Edge[i][v].f > 0) { pre[i] = -v; flag[i] = 0; alpha[i] = MIN(alpha[v], Edge[i][v].f); que[qe++] = i; } } } flag[v] = 1;//把v标记为已经访问,并且已经检查过了 } if(flag[n-1] == -1 || alpha[n-1] == 0)//如果汇点不能被标记,或者被标记了但是其第二个分量为0,则表示图中已经不存在增广路,已经达到最大流 break; int k1 = n-1, k2 = fabs( pre[k1] );//倒向追踪,如果是正向弧则该弧的实际流量加上汇点的第二分量(即可增加量),如果是反向弧,则反向弧上的实际流量减去汇点的第二个分量 int a = alpha[k1]; while( 1 ) { if(Edge[k2][k1].f < INF) Edge[k2][k1].f = Edge[k2][k1].f + a; else Edge[k1][k2].f = Edge[k1][k2].f - a; if(k2 == 0) break; k1 = k2, k2 = fabs(pre[k2]); } } int maxflow = 0; for(i = 0; i < n; ++i)//计算最大流,并且输出各个弧的流量 { for(j = 0; j < n; ++j) { if(i == 0 && Edge[i][j].f < INF) maxflow += Edge[i][j].f; if(Edge[i][j].f < INF) cout<<i<<" -> "<<j<<":"<<Edge[i][j].f<<endl; } } cout<<"MAXFLOW: "<<maxflow<<endl;}int main(){ int u, v, c, f; while(cin>>n>>m)//n是顶点数,m是边数 { if(n == 0 && m == 0) break; for(i = 0; i < n; ++i) for(j = 0; j < n; ++j) Edge[i][j].c = Edge[i][j].f = INF; for(j = 0; j < m ; ++j) { cin>>u>>v>>c>>f; Edge[u][v].c = c; Edge[u][v].f = f; } Ford_Fulkerson(); } return 0;}/**6 100 1 8 20 2 4 31 3 2 21 4 2 22 1 4 22 3 1 12 4 4 03 4 6 03 5 9 34 5 7 2*/
- 网络流 练习
- [模板练习]网络最大流
- 网络练习
- 网络流题目,准备练习网络流了~
- vs2010 网络编程练习
- BP网络练习
- 网络的练习
- 网络编程练习-fcntl
- 网络编程练习-ioctl
- Java 网络编程 练习
- python网络连接练习
- 网络编程小练习
- MVP练习网络请求
- MVP练习网络请求
- 网络编程协议练习
- poj 1273-小白算法练习 Drainage Ditches 网络流
- 练习记录0821--RecyclerView实现网络图片瀑布流
- 牛客网-- 网络基础专项练习---练习改错
- R-让函数返回多个对象
- uva548 二叉树问题 Runtime Error看过来!
- org.hibernate.MappingException: Unknown entity: com.fei.model.Student
- ExtJS做的一个信息管理界面。每一句都带有注释,可以当教科书用
- 如何去掉OO方法中的ALV的标准按钮
- 网络流 练习
- Zirco-browser:超越海豚的开源浏览器 http://www.apkbus.com/android-44306-1-1.html (出处: Android开发论坛 - 安卓开发论坛 - An
- Oracle 11g R2( + RAC) 安装 系统用户组 配置 说明
- Smarty的常用东东
- Python开发技术详解-笔记_第06章-字符串与正则表达式
- Android 系统时间日期的获取
- 在struts中的Action方法中,调用request.getInputStream() 发现无法读到任何数据
- Nginx 启动、停止、平滑重启
- MonetDB——集群