You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Boost Graph Library获取顶点v距离d的可达诱导子图?是否用bfs_visitors?

使用Boost库实现指定深度的可达诱导子图

核心思路

对应你提供的NetworkX代码逻辑,我们需要完成两步:

  1. 从顶点v出发,通过BFS筛选出深度不超过d的所有可达顶点(对应原代码中从bfs_edges提取的节点集合);
  2. 基于这些顶点生成原图的诱导子图(即包含选中顶点及它们在原图中的所有关联边)。

Boost库不需要强制使用自定义bfs_visitor,有两种可行实现方式:


方法一:使用内置BFS工具记录距离(简单易读)

这种方式借助Boost内置的record_distances工具记录每个顶点的距离,再筛选符合条件的顶点,最后复制生成子图。

代码实现

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/copy.hpp>
#include <vector>
#include <set>

// 定义图类型(以无向图为例,有向图替换为boost::directedS)
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;

Graph reachable_subgraph(const Graph& G, Vertex v, int d) {
    if (d < 0) return Graph();

    // 初始化距离数组:-1表示不可达,起点v距离为0
    std::vector<int> distances(boost::num_vertices(G), -1);
    distances[v] = 0;

    // 执行BFS并记录每个顶点的距离
    boost::breadth_first_search(G, v,
        boost::visitor(
            boost::make_bfs_visitor(
                boost::record_distances(distances.data(), boost::on_tree_edge())
            )
        )
    );

    // 收集符合条件的顶点:对应原代码逻辑,d=0时返回空,d>0时包含距离≤d的所有可达顶点
    std::set<Vertex> target_nodes;
    if (d > 0) {
        for (Vertex u : boost::make_iterator_range(boost::vertices(G))) {
            if (distances[u] != -1 && distances[u] <= d) {
                target_nodes.insert(u);
            }
        }
    }

    // 复制生成诱导子图:仅保留选中顶点及它们之间的边
    Graph subgraph;
    boost::copy_graph(G, subgraph,
        boost::vertex_filter([&target_nodes](Vertex u) {
            return target_nodes.count(u) > 0;
        })
    );

    return subgraph;
}

代码说明

  • record_distances是Boost内置的BFS访问工具,会在遍历树边时自动记录子节点的距离;
  • copy_graph结合vertex_filter,只复制选中的顶点,同时自动保留这些顶点在原图中的所有关联边,实现诱导子图的效果;
  • 针对d=0的情况,严格对应原代码逻辑,返回空的子图。

方法二:自定义BFS访问者(高效提前终止)

如果希望在BFS过程中一旦遍历到超过深度d的节点就停止处理其邻居,可以自定义bfs_visitor来实现,减少不必要的遍历。

代码实现

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/copy.hpp>
#include <vector>
#include <set>

typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::graph_traits<Graph>::edge_descriptor Edge;

// 自定义深度限制BFS访问者
struct DepthLimitedVisitor : public boost::bfs_visitor<> {
    int max_depth;
    std::set<Vertex>& target_nodes;
    std::vector<int>& distances;

    DepthLimitedVisitor(int d, std::set<Vertex>& nodes, std::vector<int>& dist)
        : max_depth(d), target_nodes(nodes), distances(dist) {}

    // 发现顶点时,若深度符合则加入集合
    void discover_vertex(Vertex u, const Graph&) {
        if (distances[u] <= max_depth) {
            target_nodes.insert(u);
        }
    }

    // 遍历树边时,设置子节点深度,超过限制则标记为已访问(不再处理其邻居)
    void tree_edge(Edge e, const Graph& G) {
        Vertex src = boost::source(e, G);
        Vertex dst = boost::target(e, G);
        distances[dst] = distances[src] + 1;

        if (distances[dst] > max_depth) {
            boost::put(boost::vertex_color, G, dst, boost::black_color);
        }
    }
};

Graph reachable_subgraph_visitor(const Graph& G, Vertex v, int d) {
    if (d < 0) return Graph();

    std::vector<int> distances(boost::num_vertices(G), -1);
    distances[v] = 0;
    std::set<Vertex> target_nodes;

    if (d > 0) {
        target_nodes.insert(v);
        std::vector<boost::default_color_type> colors(boost::num_vertices(G));
        DepthLimitedVisitor visitor(d, target_nodes, distances);
        
        boost::breadth_first_search(G, v,
            boost::visitor(visitor)
            .color_map(colors.data())
        );
    }

    // 复制生成诱导子图
    Graph subgraph;
    boost::copy_graph(G, subgraph,
        boost::vertex_filter([&target_nodes](Vertex u) {
            return target_nodes.count(u) > 0;
        })
    );

    return subgraph;
}

代码说明

  • 自定义访问者通过tree_edge方法检查子节点深度,超过d时将其标记为black_color,BFS会跳过对该节点邻居的遍历;
  • discover_vertex方法在首次访问顶点时,将符合深度要求的节点加入集合。

是否需要使用BFS访问者?

不需要强制使用。

  • 如果你追求代码简洁、易维护,方法一完全够用,借助Boost内置的工具就能完成需求;
  • 只有当你需要深度定制BFS过程(比如提前终止遍历、记录额外信息)时,才需要自定义bfs_visitor。

内容的提问来源于stack exchange,提问作者ne_tv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 09:05:25