如何遍历图表并沿着提升方式提取边缘权重?

时间:2018-05-11 17:23:56

标签: c++ boost graph depth-first-search

假设我有以下无向图

A("")--2.31--B("Hello")--1.036--C("")

其中A和C是空字符串,实数是权重。现在我想从B到A.我知道在增强中,可以用

完成
auto vp = boost::vertices(g);
for(auto vit = vp.first; vit != vp.second; ++vit)
{
  std::cout << *vit <<  " " << std::endl;
}

当我到达顶点A时,我希望能够从B中随机化字符串,基于从B到A的边缘权重的一些数学计算。所以我希望能够做类似{{1 }}

问题是我真的不知道该怎么做。我有边缘权重,它们是从我正在阅读的文件中正确导入的。如果我通过这种方式迭代,我知道如何获得权重:

g[A].name = newString(weight from B to A);

这个问题是,它会迭代图形的节点,而不一定关心任何边缘。

有什么东西可以提升我想要的东西吗?我试过从Stack Overflow中查看this implementation,我理解如何从特定的顶点开始。但是我不确定是否有办法调整此算法以使用我的边缘权重来实现我想要的,并且说实话the documentation for DFS很难理解。我相信DFS是我想要的,但我不知道如何轻松实现这一点而不会分解和编写我自己并不想做的自己的DFS。

1 个答案:

答案 0 :(得分:1)

  

现在我想从B到A.我知道在增强中,可以用[...]

完成

不,代码只是枚举顶点,即使没有边缘也没有特定顺序的顶点。

  

当我到达顶点A

“到达顶点A”是什么意思?你需要在那里有一条路径,或者你只是要枚举所有顶点并从那里遍历边缘?

  

我希望能够从B中随机化字符串,基于从B到A的边缘权重的一些数学

我将其读作“我想根据发现的边缘权重计算字符串,并更新目标顶点的标签字符串

这至少有点令人困惑,因为它暗示了无向图边缘的方向。我假设你确实想要使用方向(边缘发现期间的遍历方向)。

  

如果我通过这种方式迭代,我知道如何获得权重:[... snip ...]这个问题是这将遍历图的节点而不一定关心任何一个边缘。

咦。这完全被翻转了。那个循环确实迭代边缘,特别是。您是否交换了代码示例?

  

有什么东西可以提升我想要的东西吗?

在你知道自己想要的东西之前,这是无法回答的。

  

我相信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 likeenter image description here

添加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 likeenter image description here