如何解决提升图最大流算法——关于反向弧的作用的问题,如果它们已经存在于原始输入图中
考虑应用最大流算法的以下原始输入图:
The following code(感谢 user sehe)编译并运行良好并提供正确的输出。代码在下面复制以完成:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/range/adaptors.hpp>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
using boost::adaptors::filtered;
using Traits = boost::adjacency_list_traits<boost::vecS,boost::vecS,boost::directedS>;
using V = Traits::vertex_descriptor;
using E = Traits::edge_descriptor;
using Capacity = double;
using Color = boost::default_color_type;
struct VertexProps {
// std::string name;
Color color;
Capacity distance;
E preedcessor;
};
struct EdgeProps {
int id;
Capacity weight,residual;
E reverse;
};
using Graph = boost::adjacency_list<
boost::vecS,boost::directedS,VertexProps,// see https://stackoverflow.com/a/64744086/85371 :(
boost::property<boost::edge_capacity_t,Capacity,EdgeProps>>;
struct MyGraph {
MyGraph(size_t nnodes) : _g(nnodes) {}
void runSimulation(std::vector<std::pair<V,V>> const& arcs,std::vector<Capacity> const& capacities)
{
reconfigure(arcs,capacities);
Capacity maxflow = solve_max_flow(0,3);
auto cap = get(boost::edge_capacity,_g);
auto is_source = [this](V v) { return _g[v].color == Color::black_color; };
fmt::print("Max flow {}\nNodes {} are in source subset\n",maxflow,vertices(_g) | filtered(is_source));
for (E e : boost::make_iterator_range(edges(_g))) {
bool st_cut =
is_source(source(e,_g)) and
not is_source(target(e,_g));
fmt::print("Edge {} (id #{:2}),capacity {:3} {}\n",e,_g[e].id,cap[e],st_cut ? "(ST Cut)" : "");
}
}
private:
Graph _g;
void reconfigure(auto const& arcs,auto const& capacities)
{
assert(arcs.size() == capacities.size());
for (auto v : boost::make_iterator_range(vertices(_g))) {
// boost::clear_out_edges(v,g);
boost::clear_vertex(v,_g);
}
auto cap = get(boost::edge_capacity,_g);
auto eidx = get(&EdgeProps::id,_g);
auto rev = get(&EdgeProps::reverse,_g);
auto eindex = 0;
for (auto [fr,to] : arcs) {
auto edf = add_edge(fr,to,_g).first;
auto edr = add_edge(to,fr,_g).first;
eidx[edf] = 2 * eindex;
eidx[edr] = eidx[edf] + 1;
cap[edf] = cap[edr] = capacities[eindex];
rev[edf] = edr;
rev[edr] = edf;
++eindex;
}
}
Capacity solve_max_flow(V src,V sink)
{
return boykov_kolmogorov_max_flow(
_g,src,sink,// named arguments
boost::reverse_edge_map(get(&EdgeProps::reverse,_g))
.residual_capacity_map(get(&EdgeProps::residual,_g))
.vertex_color_map(get(&VertexProps::color,_g))
.predecessor_map(get(&VertexProps::preedcessor,_g))
.distance_map(get(&VertexProps::distance,_g))
// end named arguments
);
}
};
int main() {
MyGraph g{4};
g.runSimulation({{0,1},{0,2},{1,{2,3},3}},{10,1,10,10});
}
我的问题特别涉及弧线 (1->2) 和 (2->1)。
(a) Boost documentation 用于最大流算法要求用户为原始输入图中的每个弧明确提供反向弧。因此,在上面的示例中,有向弧 (1 -> 2) 和 (2 -> 1) 在以下代码段中两次添加到图形对象中:
auto edf = add_edge(fr,_g).first; //Arc (1->2) added,Arc (2->1) added
auto edr = add_edge(to,_g).first; //Arc (2->1) added,Arc (1->2) added
eidx[edf] = 2 * eindex;
eidx[edr] = eidx[edf] + 1;
cap[edf] = cap[edr] = capacities[eindex];
rev[edf] = edr;
rev[edr] = edf;
虽然在此特定示例中可以看到解决方案的正确性,但是否在所有情况下都能保证?也就是说,将同一弧多次(一次作为正向弧,一次作为反向弧)重复添加到图形对象中是否会导致任何内部内容在针对此问题的 boost 算法中中断?
(b) boost documentation 声明如下:
备注:虽然 push-relabel 方法指出 E^T 中的每条边都有 容量为 0,该算法的反向边为 允许承载能力。如果已经有反向边缘 输入图 G,可以使用那些。这可以将边缘数量减半 并将显着提高性能。
这是否意味着在这种特殊情况下,当我添加正向弧 (1->2) 时,我需要 NOT 明确添加反向弧 (2->1),同样当我添加添加正向弧 (2->1),我需要 NOT 显式添加反向弧 (1->2),如上面代码片段中发生的那样?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。