【问题标题】:make sub graph from boost graph using particular parent使用特定父级从提升图制作子图
【发布时间】:2017-12-27 12:39:03
【问题描述】:

我想要使用 boost 库的 C、F、H 和 D、G 等子图。 我有上面例子 C 和 D 中的所有父母。

【问题讨论】:

  • 你有什么代码。此外,这看起来像一棵树。为什么不用树?最后,为什么你始终不提 B 或 B-E?
  • 只是为了图形表示我这样画,是的我也想取出BE。这是邻接列表 boost::adjacency_list<:sets boost::vecs boost::directeds graphitem>.
  • 编辑图像以反映您评论的图形模型。此代码coliru.stacked-crooked.com/a/4ebc84d38071e75f 或此coliru.stacked-crooked.com/a/c30f1c72c752099d 将生成此图。它使用点渲染(例如webgraphviz.com
  • 请描述是什么让“D,G”成为一个有趣的子图,而不是例如“B,D,G”,甚至是“B,D,G,E”。

标签: c++ boost boost-graph


【解决方案1】:

我很难理解描述。我想我已经想通了。请考虑明确要求,而不是下次只举一个不完整的例子。

从根开始

首先我认为您的意思是找到根(零入边)并将每个子节点视为子图。

但是,这会导致:

// roots are nodes with a zero in-degree (no parents)
Vertices roots;
boost::remove_copy_if(vertices(g), back_inserter(roots), [&](Vertex v) { return boost::size(in_edges(v, g)); });

std::vector<Graph> subs;
for (Vertex root : roots) {
    for (Vertex subroot : boost::make_iterator_range(adjacent_vertices(root, g))) {

        std::set<Vertex> include;
        std::vector<boost::default_color_type> colors(n);

        boost::depth_first_visit(g, subroot, 
                boost::make_dfs_visitor(
                        boost::write_property(
                            boost::identity_property_map{},
                            inserter(include, include.end()),
                            boost::on_discover_vertex())
                    ),
                colors.data());

        std::cout << "Root " << g[root].name << ": Subtree rooted at " << g[subroot].name << " includes " << include.size() << " nodes\n";

        Filtered fg(g, boost::keep_all{}, [&](Vertex v) { return include.count(v); });
        print_graph(fg, names);
    }
}

打印Live On Coliru

Root A: Subtree rooted at B includes 4 nodes
B --> D E 
D --> G 
E --> 
G --> 
Root A: Subtree rooted at C includes 3 nodes
C --> F 
F --> H 
H --> 

确实,D 显然不是A 的孩子,所以不算数。

回到绘图板。

从树叶开始

所有包含单度子节点或叶节点的子树?

确实似乎描述了作为示例给出的“线性”子图。显然,“线性”(垂直)布局是一种任意布局选择。以下所有三种表示都与问题图完全等价:

以相反的方式看待这个突然变得更有意义:您可能想要列出从每个 leaf 节点开始的所有线性依赖关系,直到您到达也参与另一个分支的节点。

这自然涉及进行拓扑搜索并从叶节点后面列出 DAG 中的每个分支:

Live On Coliru

Vertices reverse_topological;
boost::topological_sort(g, back_inserter(reverse_topological));

bool in_path = true;
for (auto v : reverse_topological) {
    if (0 == out_degree(v, g)) { // is leaf?
        in_path = true;
        std::cout << "\nLeaf:";
    }

    in_path &= (1 == in_degree(v, g));

    if (in_path)
        std::cout << " " << names[v];
    else
        std::cout << " [" << names[v] << "]";
}

打印:

Leaf: G D
Leaf: E B
Leaf: H F C [A]

小变化:

您可以指定B 在两条路径中翻倍,具体取决于您的要求:

Live On Coliru

Vertices reverse_topological;
boost::topological_sort(g, back_inserter(reverse_topological));

bool in_path = true;
for (auto v : reverse_topological) {
    switch (out_degree(v, g)) {
        case 0:
            // start a new path
            in_path = true;
            std::cout << "\nLeaf:";
            break;
        case 1: 
            break; // still single-degree
        default: in_path = false;
    }

    if (in_path)
        std::cout << " " << names[v];
    else
        std::cout << " [" << names[v] << "]";
}

打印

Leaf: G D
Leaf: E [B]
Leaf: H F C [A]

完整列表

为了防止比特腐烂:

  • 从根开始(第一个假设)

    #include <boost/graph/adjacency_list.hpp>
    
    struct GraphItem {
        std::string name;
    };
    
    using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, GraphItem>;
    using Vertex = Graph::vertex_descriptor;
    using Vertices = std::vector<Vertex>;
    
    #include <boost/graph/filtered_graph.hpp>
    #include <boost/function.hpp>
    using Filtered = boost::filtered_graph<Graph, boost::keep_all, boost::function<bool(Vertex)>>;
    
    #include <boost/graph/graphviz.hpp>
    #include <boost/range/algorithm.hpp>
    #include <boost/graph/depth_first_search.hpp>
    #include <boost/graph/graph_utility.hpp>
    
    int main() {
    
        Graph g;
        auto names = get(&GraphItem::name, g);
    
        enum {A,B,C,D,E,F,G,H,n};
        Vertices vs {
            add_vertex({"A"}, g),
            add_vertex({"B"}, g),
            add_vertex({"C"}, g),
            add_vertex({"D"}, g),
            add_vertex({"E"}, g),
            add_vertex({"F"}, g),
            add_vertex({"G"}, g),
            add_vertex({"H"}, g),
        };
    
        assert(num_vertices(g) == n); 
        add_edge(vs[A], vs[B], g);
        add_edge(vs[A], vs[C], g);
    
        add_edge(vs[B], vs[D], g);
        add_edge(vs[B], vs[E], g);
    
        add_edge(vs[D], vs[G], g);
    
        add_edge(vs[C], vs[F], g);
        add_edge(vs[F], vs[H], g);
    
        // write_graphviz(std::cout, g, make_label_writer(names));
    
        // roots are nodes with a zero in-degree (no parents)
        Vertices roots;
        boost::remove_copy_if(vertices(g), back_inserter(roots), [&](Vertex v) { return boost::size(in_edges(v, g)); });
    
        std::vector<Graph> subs;
        for (Vertex root : roots) {
            for (Vertex subroot : boost::make_iterator_range(adjacent_vertices(root, g))) {
    
                std::set<Vertex> include;
                std::vector<boost::default_color_type> colors(n);
    
                boost::depth_first_visit(g, subroot, 
                        boost::make_dfs_visitor(
                                boost::write_property(
                                    boost::identity_property_map{},
                                    inserter(include, include.end()),
                                    boost::on_discover_vertex())
                            ),
                        colors.data());
    
                std::cout << "Root " << g[root].name << ": Subtree rooted at " << g[subroot].name << " includes " << include.size() << " nodes\n";
    
                Filtered fg(g, boost::keep_all{}, [&](Vertex v) { return include.count(v); });
                print_graph(fg, names);
            }
        }
    }
    
  • 从叶子开始(第二个假设,拓扑排序)

    #include <boost/graph/adjacency_list.hpp>
    
    struct GraphItem {
        std::string name;
    };
    
    using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, GraphItem>;
    using Vertex = Graph::vertex_descriptor;
    using Vertices = std::vector<Vertex>;
    
    #include <boost/graph/topological_sort.hpp>
    #include <iostream>
    
    int main() {
    
        Graph g;
        auto names = get(&GraphItem::name, g);
    
        {
            enum {A,B,C,D,E,F,G,H,n};
            Vertices vs {
                add_vertex({"A"}, g),
                add_vertex({"B"}, g),
                add_vertex({"C"}, g),
                add_vertex({"D"}, g),
                add_vertex({"E"}, g),
                add_vertex({"F"}, g),
                add_vertex({"G"}, g),
                add_vertex({"H"}, g),
            };
    
            assert(num_vertices(g) == n); 
            add_edge(vs[A], vs[B], g);
            add_edge(vs[A], vs[C], g);
    
            add_edge(vs[B], vs[D], g);
            add_edge(vs[B], vs[E], g);
    
            add_edge(vs[D], vs[G], g);
    
            add_edge(vs[C], vs[F], g);
            add_edge(vs[F], vs[H], g);
        }
    
        Vertices reverse_topological;
        boost::topological_sort(g, back_inserter(reverse_topological));
    
        bool in_path = true;
        for (auto v : reverse_topological) {
            if (0 == out_degree(v, g)) { // is leaf?
                in_path = true;
                std::cout << "\nLeaf:";
            }
    
            in_path &= (1 == in_degree(v, g));
    
            if (in_path)
                std::cout << " " << names[v];
            else
                std::cout << " [" << names[v] << "]";
        }
    }
    

【讨论】:

  • 拓扑排序方法的简化版本,不再需要 BidirectionalGraph 概念:coliru.stacked-crooked.com/a/1f6664ba4d23cc65
  • 好吧,我真的是新手,但我想要的是我有那个有向图(我不想更改为任何其他图类型),如果我想从主图中获取子图我应该怎么得到它。例如,1. 如果我通过 B(root),我应该得到像 (B,D,E,G) 这样的子图 2. 如果我通过 C 作为根,我应该得到像 (C,F,H) 这样的子图。通过哪个根应该是我(用户)的选择。希望它对你很清楚:)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多