【发布时间】:2017-10-07 06:52:53
【问题描述】:
我想知道是否可以使用 Boost BGL BFS 来查找从给定顶点到给定深度级别(例如 2)的所有连接顶点。如果有,怎么做?
我对访问者的概念不是很熟悉,所以知道可以使用访问者来完成会很有帮助。
谢谢!
【问题讨论】:
-
你有什么?你不能只使用距离图并过滤 xboost.org/doc/libs/1_65_1/libs/graph/doc/distance_recorder.html
我想知道是否可以使用 Boost BGL BFS 来查找从给定顶点到给定深度级别(例如 2)的所有连接顶点。如果有,怎么做?
我对访问者的概念不是很熟悉,所以知道可以使用访问者来完成会很有帮助。
谢谢!
【问题讨论】:
想到my answer yesterday,我意识到你的问题存在概念问题。
当您执行 BFS 时,您不会获得“实际”距离,而是获得“有效”距离,具体取决于碰巧访问顶点的顺序。这是有用的信息,但鉴于您正在寻找具有特定最大距离的节点,感觉就像您错过了这部分。
确实,DFS 给出了其他结果。如果您并不特别关心使用哪种搜索策略,那么有个好消息:boost::depth_first_visit 具有可选的终止函数¹
如果你替换
breadth_first_search(g, s_source,
visitor(make_bfs_visitor(record_distances(distances.data(), on_tree_edge())))
.color_map(colormap.data())
);
与
auto stop_when = [&](G::vertex_descriptor vd, ...) { return distances.at(vd)>=2.0; };
depth_first_visit(g, s_source,
make_dfs_visitor(record_distances(distances.data(), on_tree_edge())),
colormap.data(),
stop_when
);
你可以让算法做更少的工作,所以你得到第二张图片而不是第一张图片:
沿着这条路径走得更远一点,你可能会意识到你一直想要最短路径。实际上,使用dijkstra_shortest_paths 会更准确(如果边具有单位权重,则恰好等同于 BFS)。
您会注意到,在某个限制下无法修剪最短路径树。
根据您的实际可扩展性要求和其他限制,r_c_shortest_paths 可能会在这里提供帮助:
具有资源约束的最短路径问题 (SPPRC) 在有向图中寻求一条最短(最便宜、最快)的路径,该路径具有任意弧长(行程时间、成本),从一个或多个资源的源节点到目标节点约束。
例如,人们可能会寻求一条从 s 到 t 的最小长度路径,但要受到以下约束
- 总行程时间不得超过某个上限和/或
- 必须在沿路径的顶点拾取的某些货物的总量小于或等于某个容量限制和/或
- 如果两个顶点 i 和 j 在一条路径上被访问,那么 i 必须在 j 之前被访问
- 等
这个问题在强烈的意义上是 NP-hard [...]
¹ 我想 DFS 具有终止功能更自然,而 BFS 不能(因为 BFS 将在下降到搜索树中的子节点之前递归地访问所有对等点;这很容易导致由于一个分支被终止,整个树块被跳过)。不过我想类似的机制可以添加到BF访问算法中。
【讨论】:
所以。我决定尝试一下:您使用distance_recorder 这样做:
breadth_first_search(g, s_source, visitor(make_bfs_visitor(
record_distances(distances.data(), on_tree_edge())
))
);
using G = adjacency_list<>;
G::vertex_descriptor s_source = 8;
template<typename G> void save_graph(G const& g, std::string const& name, std::vector<double> const& distances);
void save_graph_filtered(double threshold, G const& g, std::string const& name, std::vector<double> const& distances);
G generate();
int main() {
G g = generate();
std::vector<double> distances(num_vertices(g));
std::vector<default_color_type> colormap(num_vertices(g));
breadth_first_search(g, s_source,
visitor(make_bfs_visitor(record_distances(distances.data(), on_tree_edge())))
.color_map(colormap.data())
);
for (auto vd : make_iterator_range(vertices(g)))
if (colormap.at(vd) == default_color_type{})
distances.at(vd) = -1;
distances[s_source] = -2;
save_graph(g, "dotgraph.txt", distances);
// show only nodes at distance <= 2:
save_graph_filtered(2.0, g, "dotgraph-filtered.txt", distances);
}
这真的很简单,因为 BGL 有它:
////////////////////////////////////////////
// generate random graph
#include <boost/graph/random.hpp>
#include <random>
size_t s_seed = 0xf5cab8bd; // std::random_device{}();
std::mt19937 s_rng {s_seed};
G generate() {
G g;
std::cout << "Seed used: " << std::hex << std::showbase << s_seed << "\n";
boost::generate_random_graph(g, 20, 30, s_rng);
return g;
}
硬编码的种子复制了这篇文章中的图像
这也可以很简单:
////////////////////////////////////////////
// filtering for threshold distance
#include <boost/graph/filtered_graph.hpp>
void save_graph_filtered(double threshold, G const& g, std::string const& name, std::vector<double> const& distances) {
filtered_graph<G, keep_all, std::function<bool(G::vertex_descriptor)>>
fg(g, {}, [&](G::vertex_descriptor vd) { return distances[vd]!=-1 && distances[vd]<=threshold; });
save_graph(fg, name, distances);
}
注意检查
distance != -1以排除无法到达的顶点。
这是最不必要的部分,但它可以制作漂亮的演示:
////////////////////////////////////////////
// graph-viz demo output
#include <fstream>
#include <algorithm>
#include <sstream>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphviz.hpp>
template<typename G>
void save_graph(G const& g, std::string const& name, std::vector<double> const& distances) {
using Vertex = typename G::vertex_descriptor;
std::ofstream dotfile;
dotfile.open(name);
auto shape = [&distances](Vertex vd) {
return (vd==s_source)?"circle":"Mrecord";
};
auto label = [&distances](Vertex vd) {
std::ostringstream name;
if (vd == s_source) name << "SOURCE";
else name << vd;
if (auto d = distances[vd]; d >= 0) name << "|distance: " << d;
return name.str();
};
auto max = 1.25* *std::max_element(distances.begin(), distances.end());
auto dist = [&distances,max](Vertex vd) {
int r = 224, g = 160, b = 160;
if (auto d = distances[vd]; d >= 0) {
r = 255.0 * (1.0 - std::clamp(d, 0.0, max)/max);
g = 255.0 * (1.0 - std::clamp(d, 0.0, max)/max);
b = 255;
}
std::ostringstream oss;
oss << std::setfill('0') << '#' << std::hex
<< std::setw(2) << r
<< std::setw(2) << g
<< std::setw(2) << b;
return oss.str();
};
dynamic_properties dp;
typed_identity_property_map<Vertex> v_;
dp.property("node_id", get(vertex_index, g));
dp.property("label", make_transform_value_property_map(label, v_));
dp.property("shape", make_transform_value_property_map(shape, v_));
//dp.property("shape", make_constant_property<Vertex>("Mrecord"s));
dp.property("style", make_constant_property<Vertex>("filled"s));
dp.property("fillcolor", make_transform_value_property_map(dist, v_));
write_graphviz_dp(dotfile, g, dp);
}
未过滤:
过滤阈值(样本中为 2.0):
【讨论】: