博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络流---预流推进(转帖)
阅读量:5250 次
发布时间:2019-06-14

本文共 2845 字,大约阅读时间需要 9 分钟。

先简单看一下主过程:

int MAXFLOW(){    hights();    prepare();    while (!Q.empty()) {	u = Q.get;	for each e in G ' (from u) push(e);		if (!fixed(u)) reCalc(u);	}}

接下来介绍算法

预流推进算法给每一个顶点一个标号h(v),表示该点到t的最短路(在残量网络中)。
第一步hights()过程,就是BFS出初始最短路,计算出每一个顶点的h(v)。

预流推进算法的特征是运用了预流来加快运算。预流说明图中的节点(除s, t),仅需要满足流入量 >= 流出量。其中流入量>流出量的接点,我们称之为活动节点。我们的算法就是不断地将活动结点,变为非活动结点,使得预流成为可行流。

算法过程prepare(),即首先将与s相连的边设为满流,并将这时产生的活动结点加入队列Q。这是算法的开始。

以后便重复以下过程直到Q为空:
(1).选出Q的一个活动顶点u。并依次判断残量网络G'中每条边(u, v),若h(u) = h(v) + 1,则顺着这里条边推流,直到Q变成非活动结点(不存在多余流量)。(Push推流过程)
(2).如果u还是活动结点。则需要对u进行重新标号:h(u) = min{h(v) + 1},其中边(u,v)存在于G' 中。然后再将u加入队列。(reCalc过程)

可以证明,通过以上算法得到的结果就是最大流。

如果该算法的Q是标准的FIFO队列,则时间复杂度为(n2m),如果是优先队列,并且标号最高的点优先的话:我们就得到了最高标号预流推进算法,其时间复杂度仅为(n2sqrt(m)),算是比较快的最大流算法了。

根据上面的伪代码, 实现算法如下

const int size = 501;const int MAX = 1 << 15;int graph[size][size];int label[size];		//标号bool visited[size];bool bfs(int st, int ed){    memset(label, -1, sizeof(label));    memset(visited, false, sizeof(visited));    label[st] = 0;    visited[st] = true;    vector < int >plist;    plist.push_back(st);    while (plist.size()) {	int p = plist[0];	plist.erase(plist.begin());	for (int i = 0; i < size; i++) {	    if (graph[i][p] > 0 && !visited[i]) {		plist.push_back(i);		visited[i] = true;		label[i] = label[p] + 1;	    }	}    }    if (label[ed] == -1) {	return false;    }    return true;}int inflow[size];		//流入量int maxFlow(){    memset(inflow, 0, sizeof(inflow));    //hights    bfs(size - 1, 0);		//end point: size - 1, start point: 0    memset(visited, false, sizeof(visited));//prepare()    vector < int >plist;    for (int i = 0; i < size; i++) {	if (graph[start][i] > 0) {	    inflow[i] = graph[start][i];	    graph[start][i] -= inflow[i];	    graph[i][start] += inflow[i];	    if (!visited[i]) {		plist.push_back(i);		visited[i] = true;	    }	}    }    while (plist.size()) {	int p = plist[0];	plist.erase(plist.begin());	visited[p] = false;	int minLabel = -1;	for (int i = 0; i < size; i++) {	    if (graph[p][i] > 0) {		if (label[p] == label[i] + 1) {		    int flow = min(inflow[p], graph[p][i]);		    inflow[p] -= flow;		    inflow[i] += flow;		    graph[p][i] -= flow;		    graph[i][p] += flow;		    if (!visited[i] && inflow[i] > 0) {			plist.push_back(i);			visited[i] = true;		    }		}	    }	}	if (inflow[p] > 0 && p != end) {	    for (int i = 0; i < size; i++) {		if (graph[p][i] > 0) {		    if (minLabel == -1 || minLabel > label[i] + 1) {			minLabel = label[i] + 1;		    }		}	    }	    if (!visited[p] && minLabel != -1 && minLabel < size)	//minLabel < size, 这个条件需要加上, 因为经过测试发现有死循环的可能	    {		for (int i = 0; i < size; i++) {		    if (label[i] + 1 == minLabel && graph[p][i] > 0) {			visited[p] = true;			label[p] = minLabel;			plist.push_back(p);			break;		    }		}	    }	}    }    return inflow[end];}

转载于:https://www.cnblogs.com/Open_Source/archive/2010/08/03/1904898.html

你可能感兴趣的文章
使用 Solr 创建 Core 并导入数据库数据
查看>>
lambda 怎么传递ref参数
查看>>
Ubuntu16.04 LTS软件中心闪退及修改阿里源
查看>>
collection 所有集合的接口。
查看>>
使用util包里自带的接口和类实现观察者模式
查看>>
Windows平台安装Redmine2.5.x
查看>>
深度剖析Spark分布式执行原理
查看>>
fedora下体验gentoo安装
查看>>
IOS企业开发者帐号申请
查看>>
Vector Clock/Version Clock
查看>>
单例模式 项目应用
查看>>
单链表中环的问题
查看>>
使用remoting 代替c# web service实现航班eterm命令发送和接收
查看>>
hdfs fsimage namenode 应该设置多少堆内存合适
查看>>
实习总结
查看>>
Could not Open Install.Log File解决方法
查看>>
指令常用寻址方式
查看>>
指纹识别缺点
查看>>
ios面试题2
查看>>
执行sql update use c#
查看>>