【问题标题】:Is it possible to change breadth first search termination condition in BGL?是否可以在 BGL 中更改广度优先搜索终止条件?
【发布时间】:2013-04-03 07:08:27
【问题描述】:

我是 BGL(增强图形库)的新手。我正在学习breadth_first_search 界面,它看起来很方便。但是,在我的应用程序中,当满足其他一些终止条件(例如搜索空间节点数满足最大值)时,我需要削减广度优先搜索。

我可以用 BFSVisitor 添加新的终止条件还是有什么其他技巧?

谢谢!

【问题讨论】:

  • 嗨!你的问题解决了吗?
  • 我没有,只是写了我自己的实现:)
  • 我能够提前终止使用标准库方法的 _d_fs 搜索和使用异常的 _b_fs 搜索。你认为我应该发布一个解释它的答案吗?
  • 我非常期待看到您的解决方案。很酷!

标签: boost breadth-first-search boost-graph


【解决方案1】:

在@yuyoyuppe 评论之后(有点晚了),您可以创建一个代理访问者,该访问者将包装实际访问者并在满足给定谓词时抛出。我选择解决的实现为您提供了在discover_vertexexamine_edge 上运行谓词的能力。首先我们定义一个默认谓词总是返回 false:

namespace details {

struct no_halting {
    template <typename GraphElement, typename Graph>
    bool operator()(GraphElement const&, Graph const&) {
        return false;
    }
};
} // namespace details

然后是模板本身。

template <typename VertexPredicate = details::no_halting,
          typename EdgePredicate = details::no_halting,
          typename BFSVisitor = boost::default_bfs_visitor>
struct bfs_halting_visitor : public BFSVisitor {
    // ... Actual implementation ...
private:
    VertexPredicate vpred;
    EdgePredicate epred;
};

需要 3 个模板参数:

  1. 每次调用discover_vertex时应用一个顶点谓词(每个顶点最多一次)
  2. 边谓词,每次调用 examine_edge 时应用(每个边最多一次)
  3. 我们将继承的实际访问者实现

要构建它,我们只需初始化基本访问者和我们的两个谓词:

template <typename VPred, typename EPred, typename ... VisArgs>
bfs_halting_visitor(VPred&& vpred, EPred&& epred, VisArgs&&... args) :
                    BFSVisitor(std::forward<VisArgs>(args)...),
                    vpred(vpred), epred(epred) {}

然后,我们必须创建一个(私有)代理函数来执行对基本实现的适当调用并检查谓词:

template <typename Pred, typename R, typename ... FArgs, typename ... Args>
void throw_on_predicate(R (BFSVisitor::*base_fct)(FArgs...), Pred&& pred, Args&&... args) {
    bool result = pred(args...);
    (this->*base_fct)(std::forward<Args>(args)...);
    if (result) {
        throw std::runtime_error("A predicate returned true");
    }
}

当然,我懒惰地使用了std::runtime_error,但您应该定义自己的异常类型,派生自std::exception 或您使用的任何基本异常类。

现在我们可以轻松定义我们的两个回调:

template <typename Edge, typename Graph>
void examine_edge(Edge&& e, Graph&& g) {
    throw_on_predicate(&BFSVisitor::template examine_edge<Edge, Graph>, epred,
                       std::forward<Edge>(e), std::forward<Graph>(g));
}

template <typename Vertex, typename Graph>
void discover_vertex(Vertex&& v, Graph&& g) {
    throw_on_predicate(&BFSVisitor::template discover_vertex<Vertex, Graph>, vpred,
                       std::forward<Vertex>(v), std::forward<Graph>(g));
}

我们将在自定义顶点谓词上测试我们的设施,该谓词在发现第 N 个顶点时返回 true。

struct VertexCounter {
    VertexCounter(std::size_t limit) : count(0), limit(limit) {}
    VertexCounter() : VertexCounter(0) {}

    template <typename V, typename G>
    bool operator()(V&&, G&&) {
        return ((++count) > limit);
    }
private:
    std::size_t count;
    std::size_t const limit;
};

要在给定的图上执行 bfs,这很容易:

Graph graph = get_graph();
Vertex start_vertex;
bfs_halting_visitor<VertexCounter> vis(VertexCounter(2), details::no_halting());
try {
    boost::breadth_first_search(graph, start_vertex, boost::visitor(vis));
} catch (std::runtime_error& e) {
    std::cout << e.what() << std::endl;
}

live demo on Coliru 可帮助您了解所有的实际情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-25
    • 2010-12-17
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    相关资源
    最近更新 更多