Graph with two types of nodes

允我心安 提交于 2019-12-12 09:54:31

问题


I'm writing a program using C++ and Boost Graph Library (BGL). I have two classes named Buildings and Contracts. I need to make a graph which represents connection relations between them all. So the graph should have two types of vertices (B and C), be oriented and include edges B->B, C->C and B->C.

  1. Is it possible?
  2. If yes, how to implement this?

EDIT

Actually, I tried to avoid connections between different type nodes, so I had two separate graphs. But it made my model far more complicated because of implementation of in fact existing relation between B and C. Edge B1->B2 shows that it's necessary to have already built B1 to build B2. C1->C2 is actually the same, but in terms of contracts. B->C shows, that a contract C can be completed in building B.


回答1:


I already left a comment asking for the goal:

I'd be happy to show (several) approaches iff you would be able to describe the problem you're trying to solve. Because at this point it's not at all clear what you'd require the integrated datastructure for (I'm unable to think of algorithms that would benefit from having both the B-B, C-C, B-C edges.). Off the top of my mind 2 separate graphs, an implicit graph that conjoins them, or a single graph with optionally filtered views would do. Filtering could be done by some kind of (dynamic) type switch OR it could be done using some kind of external/intrusive index. – sehe 31 mins ago

Regardless of that, you can use boost::variant to do exactly what the question asks (that is, probably an X/Y problem question):

Demo

Live On Wandbox

#include <boost/graph/adj_list_serialize.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/variant.hpp>
#include <fstream>
using namespace boost;

namespace Nodes {
    struct Building { std::string id; };
    struct Contract { std::string id; };

    static inline std::ostream& operator<<(std::ostream& os, Building const& b) { return os << "Building " << b.id; }
    static inline std::ostream& operator<<(std::ostream& os, Contract const& b) { return os << "Contract " << b.id; }

    std::string id_of(Building const& b) { return b.id; }
    std::string id_of(Contract const& c) { return c.id; }
    std::string shape_of(Building const& b) { return "circle"; }
    std::string shape_of(Contract const& c) { return "diamond"; }
}

using Nodes::Building;
using Nodes::Contract;
using Vertex = boost::variant<Building, Contract>;

std::string id_of(Vertex const& v) {
    return boost::apply_visitor([](auto const& node) { return id_of(node); }, v);
}
std::string shape_of(Vertex const& v) {
    return boost::apply_visitor([](auto const& node) { return shape_of(node); }, v);
}

typedef adjacency_list<vecS, vecS, directedS, Vertex> Graph;

int main() {
    Graph g;
    auto office1    = add_vertex(Building{ "office1" }, g);
    auto office2    = add_vertex(Building{ "office2" }, g);
    auto warehouse1 = add_vertex(Building{ "warehouse1" }, g);
    auto contract1  = add_vertex(Contract{ "contract1" }, g);
    auto contract2  = add_vertex(Contract{ "contract2" }, g);

    add_edge(office1, office2, g);
    add_edge(warehouse1, contract1, g);
    add_edge(contract2, contract1, g);

    {
        std::ofstream dot_file("graph.dot");
        dynamic_properties dp;

        dp.property("node_id", boost::make_transform_value_property_map(&::id_of, boost::get(boost::vertex_bundle, g)));
        dp.property("shape", boost::make_transform_value_property_map(&::shape_of, boost::get(boost::vertex_bundle, g)));
        dp.property("label", boost::make_transform_value_property_map(
            [](Vertex const& v) { return boost::lexical_cast<std::string>(v); },
            boost::get(boost::vertex_bundle, g)));

        write_graphviz_dp(dot_file, g, dp);
    }

    print_graph(g);
}

Prints

0 --> 1
1 -->
2 --> 3
3 -->
4 --> 3

As well as generating graph.dot for the following graph:

The source .dot looks like this:

digraph G {
office1 [label="Building office1", shape=circle];
office2 [label="Building office2", shape=circle];
warehouse1 [label="Building warehouse1", shape=circle];
contract1 [label="Contract contract1", shape=diamond];
contract2 [label="Contract contract2", shape=diamond];
office1->office2 ;
warehouse1->contract1 ;
contract2->contract1 ;
}

And I rendered it online using https://dreampuf.github.io/GraphvizOnline/



来源:https://stackoverflow.com/questions/45484144/graph-with-two-types-of-nodes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!