现在我想从 B 到 A。我知道在 boost 中,可以使用 [...]
不,代码只是枚举顶点,即使是那些没有边且没有特定顺序的顶点。
当我到达顶点 A
“到达顶点 A”是什么意思?您需要在那里有一条路径,还是只是要枚举所有顶点并从那里遍历边?
我希望能够根据从 B 到 A 的边权重的一些数学计算来随机化 B 中的字符串
我将其读作“我想根据发现的边的权重计算一个字符串,并更新目标顶点的标签字符串。
这至少有点令人困惑,因为它暗示了无向图边缘的方向。我假设您确实想使用一个方向(边缘发现期间的遍历方向)。
如果我通过这种方式迭代,我知道如何获得权重:[...snip...] 问题在于,这将遍历图形的节点,而不必关心任何边缘。
嗯。这完全颠倒过来了。该循环确实迭代边缘,特别是。您是否交换了代码示例?
在 boost 中有什么东西可以满足我的需求吗?
在您知道自己想要什么之前,这是无法回答的。
我相信 DFS 是我想要的
好的...让我们开始吧:
示例图
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
让我们定义一个可以存储标签 (name) 和权重的图:
struct Vertex { std::string name; };
struct Edge { double weight; };
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge>;
现在,让我们以 Graphviz 格式打印示例图:
Graph make_sample();
void dump(Graph&);
int main() {
Graph g = make_sample();
dump(g);
}
这有点像作弊,但通常有助于从大局开始并隐藏细节,所以让我们实现make_sample:
Graph make_sample() {
Graph g;
auto A = add_vertex({""}, g);
auto B = add_vertex({"Hello"}, g);
auto C = add_vertex({""}, g);
add_edge(A, B, {2.31}, g);
add_edge(B, C, {1.036}, g);
return g;
}
还有dump:
#include <boost/graph/graphviz.hpp>
void dump(Graph& g) {
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Vertex::name, g));
dp.property("label", get(&Edge::weight, g));
write_graphviz_dp(std::cout, g, dp);
}
图looks like这个:
添加 DFS
搜索很简单:
#include <boost/graph/depth_first_search.hpp>
struct Visitor : boost::default_dfs_visitor {
};
void operate_on(Graph& g) {
Visitor vis;
std::vector<boost::default_color_type> color(num_vertices(g));
boost::depth_first_search(g, vis, color.data());
}
但你想施展魔法:
struct Visitor : boost::default_dfs_visitor {
void examine_edge(Graph::edge_descriptor e, const Graph& g) const {
std::cout << "Examining edge " << e << "\n";
}
};
现在,我们打印:
Examining edge (0,1)
Examining edge (1,0)
Examining edge (1,2)
Examining edge (2,1)
现在,让我们检查相关顶点的属性:
Vertex const& s = g[source(e, g)];
Vertex const& t = g[target(e, g)];
现在你可以做一些逻辑了:
if (s.name.empty() && !t.name.empty()) { // use your own logic here
std::cout << "Updating label for '" << t.name << "' in edge " << e << "\n";
}
已经打印的:
Updating label for 'Hello' in edge (0,1)
Updating label for 'Hello' in edge (2,1)
写入 - 访问
出于安全原因,Graph 由访客中的const& 接收。为了能够改变,我们需要一个可写的引用。一种方法是在访问者中存储Graph&:
struct Visitor : boost::default_dfs_visitor {
Graph& _g;
Visitor(Graph& g) : _g(g) {}
void examine_edge(Graph::edge_descriptor e, const Graph&) const {
// get vertex bundles
Vertex& s = _g[source(e, _g)];
Vertex& t = _g[target(e, _g)];
if (s.name.empty() && !t.name.empty()) { // use your own logic here
t.name += '(' + std::to_string(_g[e].weight) + ')';
}
return;
}
};
也许更惯用的方法是使用具有类似效果的属性映射:
struct Visitor : boost::default_dfs_visitor {
boost::property_map<Graph, std::string Vertex::*>::type _name;
boost::property_map<Graph, double Edge::*>::const_type _weight;
Visitor(Graph& g)
: _name(get(&Vertex::name, g)),
_weight(get(&Edge::weight, static_cast<Graph const&>(g)))
{ }
void examine_edge(Graph::edge_descriptor e, const Graph& g) const {
auto& sname = _name[source(e, g)];
auto& tname = _name[target(e, g)];
if (sname.empty() && !tname.empty()) { // use your own logic here
tname += '(' + std::to_string(_weight[e]) + ')';
}
return;
}
};
警告:算法期间的写访问是危险的。注意不要违反算法的前置条件/不变量
完整演示
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
struct Vertex { std::string name; };
struct Edge { double weight; };
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge>;
Graph make_sample();
void dump(Graph&);
void operate_on(Graph&);
int main() {
Graph g = make_sample();
operate_on(g);
dump(g);
}
Graph make_sample() {
Graph g;
auto A = add_vertex({""}, g);
auto B = add_vertex({"Hello"}, g);
auto C = add_vertex({""}, g);
add_edge(A, B, {2.31}, g);
add_edge(B, C, {1.036}, g);
return g;
}
#include <boost/graph/graphviz.hpp>
void dump(Graph& g) {
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Vertex::name, g));
dp.property("label", get(&Edge::weight, g));
write_graphviz_dp(std::cout, g, dp);
}
#include <boost/graph/depth_first_search.hpp>
struct Visitor : boost::default_dfs_visitor {
boost::property_map<Graph, std::string Vertex::*>::type _name;
boost::property_map<Graph, double Edge::*>::const_type _weight;
Visitor(Graph& g)
: _name(get(&Vertex::name, g)),
_weight(get(&Edge::weight, static_cast<Graph const&>(g)))
{ }
void examine_edge(Graph::edge_descriptor e, const Graph& g) const {
auto& sname = _name[source(e, g)];
auto& tname = _name[target(e, g)];
if (sname.empty() && !tname.empty()) { // use your own logic here
tname += '(' + std::to_string(_weight[e]) + ')';
}
}
};
void operate_on(Graph& g) {
Visitor vis { g };
std::vector<boost::default_color_type> color(num_vertices(g));
boost::depth_first_search(g, vis, color.data());
}
打印:
graph G {
0 [label=""];
1 [label="Hello(2.310000)(1.036000)"];
2 [label=""];
0--1 [label=2.31];
1--2 [label=1.036];
}
哪个looks like: