我正在解决一个优化问题,除其他外,我必须最大化流网络。我实现了一个基于 C++ 代码的流最大化算法,该算法基于Sedgewick “Java 中的算法,第三版,第 5 部分:图形算法”一书中出现的以下java 代码,该算法使用基于顶点的 PREFLOW- 最大化网络流-推送算法:
class NetworkMaxFlow
{ private Network G; private int s, t;
private int[] h, wt;
private void initheights()
NetworkMaxFlow(Network G, int s, int t)
{ this.G = G; this.s = s; this.t = t;
wt = new int[G.V()]; h = new int[G.V()];
initheights();
intGQ gQ = new intGQ(G.V());
gQ.put(s); wt[t] = -(wt[s] = Edge.M*G.V());
while (!gQ.empty())
{ int v = gQ.get();
AdjList A = G.getAdjList(v);
for (Edge e = A.beg(); !A.end(); e = A.nxt())
{ int w = e.other(v), cap = e.capRto(w);
int P = cap < wt[v] ? cap : wt[v];
if (P > 0 && v == s || h[v] == h[w]+1) // first observation (see below)
{ e.addflowRto(w, P);
wt[v] -= P; wt[w] += P;
if ((w != s) && (w != t)) gQ.put(w); // enqueue w if it is not source or sink
}
}
if (v != s && v != t && wt[v] > 0) // why check v != t if t never enter the queue?
{ h[v]++; gQ.put(v); }
}
}
}
我的实现,基于那段代码,无法最大化下面的网络
执行后,产生的流程如下
有了这个流程,流量值是8,但是最大值是9,如下图的
流程
所示
据我了解,该算法与书中的解释是一致的。但是,我看到了两件奇怪的事情
- 源中没有明确的预流阶段。当谓词为真时,它被包含在
while
并首先执行一次。P > 0 && v == s
也许这样做是为了缩短代码 - 根据我的理解和书中的论述,sink 永远不会进入队列。但是,当高度增加时,代码会检查 v != t。这有什么原因吗?
这是我在 C++ 中实现该算法的摘录
template <class Net, class Q_Type> typename Net::Flow_Type
generic_preflow_vertex_push_maximum_flow(Net & net)
{
init_height_in_nodes(net); // breadth first traverse from sink to
// source. Nodes are labeled with their
// minimal distance (in nodes) to sink
auto source = net.get_source();
auto sink = net.get_sink();
using Itor = __Net_Iterator<Net>;
Q_Type q; // generic queue (can be fifo, heap or random) of active nodes
// preflow: floods all nodes connected to the source
for (Itor it(source); it.has_curr(); it.next())
{
auto arc = it.get_curr();
arc->flow = arc->cap; // saturate arc to its maximum
auto tgt = net.get_tgt_node(arc);
put_in_active_queue(q, tgt);
assert(node_height<Net>(source) == node_height<Net>(tgt) + 1);
assert(not is_residual<Net>(source, arc));
}
while (not q.is_empty()) // while there are active nodes
{
auto src = get_from_active_queue(q);
auto excess = net.get_in_flow(src) - net.get_out_flow(src);
for (Itor it(src); it.has_curr(); it.next())
{
auto arc = it.get_curr();
auto tgt = net.get_connected_node(arc, src);
if (node_height<Net>(src) != node_height<Net>(tgt) + 1)
continue; // this arc is not eligible
typename Net::Flow_Type flow_to_push;
if (is_residual<Net>(src, arc))
{
flow_to_push = std::min(arc->flow, excess);
arc->flow -= flow_to_push;
}
else
{
flow_to_push = std::min(arc->cap - arc->flow, excess);
arc->flow += flow_to_push;
}
excess -= flow_to_push;
if (tgt != sink and tgt != source)
put_in_active_queue(q, tgt);
}
if (excess > 0) // src still active?
{
node_height<Net>(src)++;
put_in_active_queue(q, src);
}
}
return net.flow_value(); // sum of all outing flow from source
}
¿ 有人发现我的代码和 Sedgewick 的代码之间存在逻辑上的不一致?我的印象是我的代码(也许还有 Sedgewick)没有正确处理高度的增加。但我不明白为什么
我展示了无法最大化的网络的详细执行跟踪(跟踪从 while 的第一个 q.get() 开始。括号中的值是高度的值。IN 是到节点的传入流。OUT即将到来的一个。
例如,该行
4104 (2) --> 0 (1) pushing 1 from 4104 toward 0
指符合条件的弧 4104-->0。节点4104的高度为2,节点0的高度为1。表述“推1”意味着1个单位的流被推向目标节点(0)。该行================
分隔每个队列提取。队列是先进先出的,其状态在每次处理结束时打印。
请注意,多次推送或减少零流量单元,但目标节点变为活动状态。
这是执行跟踪
Initial Queue = 4104 4105 4106 4107 4108
Active node 4104 Height = 2 IN = 1 OUT = 0
4104 (2) --> source (3) not eligible
4104 (2) --> 0 (1) pushing 1 from 4104 toward 0
4104 (2) --> 1 (1) pushing 0 from 4104 toward 1
4104 (2) --> 2 (1) pushing 0 from 4104 toward 2
4104 (2) --> 4 (1) pushing 0 from 4104 toward 4
Excess = 0
Queue = 4105 4106 4107 4108 0 1 2 4
================
Active node 4105 Height = 2 IN = 3 OUT = 0
4105 (2) --> source (3) not eligible
4105 (2) --> 1 (1) pushing 1 from 4105 toward 1
4105 (2) --> 4 (1) pushing 1 from 4105 toward 4
4105 (2) --> 6 (1) pushing 1 from 4105 toward 6
Excess = 0
Queue = 4106 4107 4108 0 1 2 4 6
================
Active node 4106 Height = 2 IN = 1 OUT = 0
4106 (2) --> source (3) not eligible
4106 (2) --> 1 (1) pushing 1 from 4106 toward 1
4106 (2) --> 5 (1) pushing 0 from 4106 toward 5
Excess = 0
Queue = 4107 4108 0 1 2 4 6 5
================
Active node 4107 Height = 2 IN = 1 OUT = 0
4107 (2) --> source (3) not eligible
4107 (2) --> 1 (1) pushing 1 from 4107 toward 1
4107 (2) --> 2 (1) pushing 0 from 4107 toward 2
4107 (2) --> 3 (1) pushing 0 from 4107 toward 3
4107 (2) --> 4 (1) pushing 0 from 4107 toward 4
4107 (2) --> 6 (1) pushing 0 from 4107 toward 6
Excess = 0
Queue = 4108 0 1 2 4 6 5 3
================
Active node 4108 Height = 2 IN = 3 OUT = 0
4108 (2) --> source (3) not eligible
4108 (2) --> 1 (1) pushing 1 from 4108 toward 1
4108 (2) --> 2 (1) pushing 1 from 4108 toward 2
4108 (2) --> 4 (1) pushing 1 from 4108 toward 4
4108 (2) --> 5 (1) pushing 0 from 4108 toward 5
4108 (2) --> 6 (1) pushing 0 from 4108 toward 6
Excess = 0
Queue = 0 1 2 4 6 5 3
================
Active node 0 Height = 1 IN = 1 OUT = 0
0 (1) --> sink (0) pushing 1 from 0 toward sink
0 (1) --> 4104 (2) not eligible
Excess = 0
Queue = 1 2 4 6 5 3
================
Active node 1 Height = 1 IN = 4 OUT = 0
1 (1) --> sink (0) pushing 2 from 1 toward sink
1 (1) --> 4105 (2) not eligible
1 (1) --> 4106 (2) not eligible
1 (1) --> 4107 (2) not eligible
1 (1) --> 4108 (2) not eligible
Excess = 2 1 goes back onto queue with label 2
Queue = 2 4 6 5 3 1
================
Active node 2 Height = 1 IN = 1 OUT = 0
2 (1) --> sink (0) pushing 1 from 2 toward sink
2 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 4 6 5 3 1
================
Active node 4 Height = 1 IN = 2 OUT = 0
4 (1) --> sink (0) pushing 2 from 4 toward sink
4 (1) --> 4105 (2) not eligible
4 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 6 5 3 1
================
Active node 6 Height = 1 IN = 1 OUT = 0
6 (1) --> sink (0) pushing 1 from 6 toward sink
6 (1) --> 4105 (2) not eligible
Excess = 0
Queue = 5 3 1
================
Active node 5 Height = 1 IN = 0 OUT = 0
5 (1) --> sink (0) pushing 0 from 5 toward sink
Excess = 0
Queue = 3 1
================
Active node 3 Height = 1 IN = 0 OUT = 0
3 (1) --> sink (0) pushing 0 from 3 toward sink
Excess = 0
Queue = 1
================
Active node 1 Height = 2 IN = 4 OUT = 2
1 (2) --> 4105 (2) not eligible
1 (2) --> 4106 (2) not eligible
1 (2) --> 4107 (2) not eligible
1 (2) --> 4108 (2) not eligible
Excess = 2 1 goes back onto queue with label 3
Queue = 1
================
Active node 1 Height = 3 IN = 4 OUT = 2
1 (3) --> 4105 (2) Reducing 1 from 1 toward 4105
1 (3) --> 4106 (2) Reducing 1 from 1 toward 4106
1 (3) --> 4107 (2) Reducing 0 from 1 toward 4107
1 (3) --> 4108 (2) Reducing 0 from 1 toward 4108
Excess = 0
Queue = 4105 4106 4107 4108
================
Active node 4105 Height = 2 IN = 3 OUT = 2
4105 (2) --> source (3) not eligible
4105 (2) --> 1 (3) not eligible
Excess = 1 4105 goes back onto queue with label 3
Queue = 4106 4107 4108 4105
================
Active node 4106 Height = 2 IN = 1 OUT = 0
4106 (2) --> source (3) not eligible
4106 (2) --> 1 (3) not eligible
4106 (2) --> 5 (1) pushing 1 from 4106 toward 5
Excess = 0
Queue = 4107 4108 4105 5
================
Active node 4107 Height = 2 IN = 1 OUT = 1
4107 (2) --> source (3) not eligible
4107 (2) --> 2 (1) pushing 0 from 4107 toward 2
4107 (2) --> 3 (1) pushing 0 from 4107 toward 3
4107 (2) --> 4 (1) pushing 0 from 4107 toward 4
4107 (2) --> 6 (1) pushing 0 from 4107 toward 6
Excess = 0
Queue = 4108 4105 5 2 3 4 6
================
Active node 4108 Height = 2 IN = 3 OUT = 3
4108 (2) --> source (3) not eligible
4108 (2) --> 5 (1) pushing 0 from 4108 toward 5
4108 (2) --> 6 (1) pushing 0 from 4108 toward 6
Excess = 0
Queue = 4105 5 2 3 4 6
================
Active node 4105 Height = 3 IN = 3 OUT = 2
4105 (3) --> source (3) not eligible
4105 (3) --> 1 (3) not eligible
Excess = 1 4105 goes back onto queue with label 4
Queue = 5 2 3 4 6 4105
================
Active node 5 Height = 1 IN = 1 OUT = 0
5 (1) --> sink (0) pushing 1 from 5 toward sink
5 (1) --> 4106 (2) not eligible
Excess = 0
Queue = 2 3 4 6 4105
================
Active node 2 Height = 1 IN = 1 OUT = 1
2 (1) --> sink (0) pushing 0 from 2 toward sink
2 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 3 4 6 4105
================
Active node 3 Height = 1 IN = 0 OUT = 0
3 (1) --> sink (0) pushing 0 from 3 toward sink
Excess = 0
Queue = 4 6 4105
================
Active node 4 Height = 1 IN = 2 OUT = 2
4 (1) --> 4105 (4) not eligible
4 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 6 4105
================
Active node 6 Height = 1 IN = 1 OUT = 1
6 (1) --> sink (0) pushing 0 from 6 toward sink
6 (1) --> 4105 (4) not eligible
Excess = 0
Queue = 4105
================
Active node 4105 Height = 4 IN = 3 OUT = 2
4105 (4) --> source (3) Reducing 1 from 4105 toward source
4105 (4) --> 1 (3) pushing 0 from 4105 toward 1
Excess = 0
Queue = 1
================
Active node 1 Height = 3 IN = 2 OUT = 2
1 (3) --> 4107 (2) Reducing 0 from 1 toward 4107
1 (3) --> 4108 (2) Reducing 0 from 1 toward 4108
Excess = 0
Queue = 4107 4108
================
Active node 4107 Height = 2 IN = 1 OUT = 1
4107 (2) --> source (3) not eligible
4107 (2) --> 2 (1) pushing 0 from 4107 toward 2
4107 (2) --> 3 (1) pushing 0 from 4107 toward 3
4107 (2) --> 4 (1) pushing 0 from 4107 toward 4
4107 (2) --> 6 (1) pushing 0 from 4107 toward 6
Excess = 0
Queue = 4108 2 3 4 6
================
Active node 4108 Height = 2 IN = 3 OUT = 3
4108 (2) --> source (3) not eligible
4108 (2) --> 5 (1) pushing 0 from 4108 toward 5
4108 (2) --> 6 (1) pushing 0 from 4108 toward 6
Excess = 0
Queue = 2 3 4 6 5
================
Active node 2 Height = 1 IN = 1 OUT = 1
2 (1) --> sink (0) pushing 0 from 2 toward sink
2 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 3 4 6 5
================
Active node 3 Height = 1 IN = 0 OUT = 0
3 (1) --> sink (0) pushing 0 from 3 toward sink
Excess = 0
Queue = 4 6 5
================
Active node 4 Height = 1 IN = 2 OUT = 2
4 (1) --> 4105 (4) not eligible
4 (1) --> 4108 (2) not eligible
Excess = 0
Queue = 6 5
================
Active node 6 Height = 1 IN = 1 OUT = 1
6 (1) --> sink (0) pushing 0 from 6 toward sink
6 (1) --> 4105 (4) not eligible
Excess = 0
Queue = 5
================
Active node 5 Height = 1 IN = 1 OUT = 1
5 (1) --> sink (0) pushing 0 from 5 toward sink
5 (1) --> 4106 (2) not eligible
Excess = 0
Queue =