网络流---预流推进(转帖)

先简单看一下主过程:

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];
}

posted @ 2010-08-03 08:17  open source  阅读(1827)  评论(3编辑  收藏