Search code examples
c++boostboost-graph

Create undirected graph by boost graph same as the input


I want to create the graph as following, first column is vertex, other's are adjacency vertex

  • 1 2 3 4 7
  • 2 1 3 4
  • 3 1 2 4
  • 4 1 2 3 5
  • 5 4 6 7 8
  • 6 5 7 8
  • 7 1 5 6 8
  • 8 5 6 7

I add the edges into the graph like this

using MinCutG = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;

MinCutG graph;
std::vector<std::vector<int> > input{ {1,2,3,4,7}, {2,1,3,4}, {3,1,2,4},
            {4,1,2,3,5}, {5,4,6,7,8}, {6,5,7,8}, {7,1,5,6,8}, {8,5,6,7}};
for(auto const &data : input){
    auto begin = std::begin(data);
    auto end = std::end(data);
    if(begin != end){
        auto const Vertex = *begin;
        ++begin;
        while(begin != end){
            boost::add_edge(Vertex, *begin, graph);        
            ++begin;
        }
    }
}

print the graph

template<typename Graph>
void print_adjacent_vertex(Graph const &g)
{
    for (auto vertex = vertices(g); vertex.first != vertex.second; ++vertex.first){
        std::cout << *vertex.first << " is connected with ";
        for (auto neighbour = adjacent_vertices(*vertex.first, g);
             neighbour.first != neighbour.second; ++neighbour.first){
            std::cout << *neighbour.first << " ";
        }
        std::cout<<std::endl;
    }
}

I expect the outputshould same as the input, but it is not The results are

  • 1 is connected with 2 3 4 7 2 3 4 7
  • 2 is connected with 1 1 3 4 3 4
  • 3 is connected with 1 2 1 2 4 4
  • 4 is connected with 1 2 3 1 2 3 5 5
  • 5 is connected with 4 4 6 7 8 6 7 8
  • 6 is connected with 5 5 7 8 7 8
  • 7 is connected with 1 5 6 1 5 6 8 8
  • 8 is connected with 5 6 7 5 6 7

my expected results

  • 1 is connected with 2 3 4 7
  • 2 is connected with 1 3 4
  • 3 is connected with 1 2 4
  • 4 is connected with 1 2 3 5
  • 5 is connected with 4 6 7 8
  • 6 is connected with 6 5 7 8
  • 7 is connected with 7 1 5 6 8
  • 8 is connected with 8 5 6 7

Solution

  • In short, using setS for the OutEdgeList template parameter will disable parallel edges, resulting in the desired output.

    The first template parameter to boost::adjacency_list is OutEdgeList and it controls certain graph behaviors, such as allowing or disallowing parallel edges. In the case of undirected MinCutG graph, vecS is used as the OutEdgeList which will enable parallel edges. For example, if an undirected graph supported parallel edges, then with:

    add_edge(1, 2, graph); // Vertex 1 and 2 are adjacent to one another via edge A.
    add_edge(2, 1, graph); // Vertex 1 and 2 are adjacent to one another via edge B,
                           // which is parallel to edge A.
    

    The adjacent_vertices() for vertex 1 will contain vertex 2 twice, once for each edge (A and B).

    As noted in the documentation, parallel edges can be disabled by using setS or hash_setS selectors for the OutEdgeList. For example, change:

    using MinCutG = boost::adjacency_list<
      boost::vecS, // OutEdgeList with parallel edges
      boost::vecS,
      boost::undirectedS>;
    

    to:

    using MinCutG = boost::adjacency_list<
      boost::setS, // OutEdgeList with no parallel edges
      boost::vecS,
      boost::undirectedS>;
    

    Here is an example using the original code and only changing the OutEdgeList from vecS to setS:

    #include <iostream>
    #include <vector>
    #include <boost/graph/adjacency_list.hpp>
    
    template<typename Graph>
    void print_adjacent_vertex(Graph const &g)
    {
        for (auto vertex = vertices(g); vertex.first != vertex.second; 
             ++vertex.first){
            std::cout << *vertex.first << " is connected with ";
            for (auto neighbour = adjacent_vertices(*vertex.first, g);
                 neighbour.first != neighbour.second; ++neighbour.first){
                std::cout << *neighbour.first << " ";
            }
            std::cout<<std::endl;
        }
    }
    
    int main()
    {
        using MinCutG = boost::adjacency_list<
            boost::setS, boost::vecS, boost::undirectedS>;
    
        MinCutG graph;
        std::vector<std::vector<int> > input
        {
            {1,2,3,4,7},
            {2,1,3,4},
            {3,1,2,4},
            {4,1,2,3,5},
            {5,4,6,7,8},
            {6,5,7,8},
            {7,1,5,6,8},
            {8,5,6,7}
        };
    
        for(auto const &data : input){
            auto begin = std::begin(data);
            auto end = std::end(data);
            if(begin != end){
                auto const Vertex = *begin;
                ++begin;
                while(begin != end){
                    boost::add_edge(Vertex, *begin, graph);        
                    ++begin;
                }
            }
        }
        print_adjacent_vertex(graph);
    }
    

    Which produces the following output:

    0 is connected with 
    1 is connected with 2 3 4 7 
    2 is connected with 1 3 4 
    3 is connected with 1 2 4 
    4 is connected with 1 2 3 5 
    5 is connected with 4 6 7 8 
    6 is connected with 5 7 8 
    7 is connected with 1 5 6 8 
    8 is connected with 5 6 7