I am working with a graphing using Boost library.
The graph is defined as follows.
typedef boost::adjacency_list<boost::setS,boost::setS,boost::undirectedS, uint32_t, float> AdjacencyList;
After creating the graph using appropriate data, in a separate function I want to print the adjacent_vertices of each vertex with their appropriate edge weight as computed in the beginning.
The creating part works well but when I want to extract adjacent vertices I dont get the values.
typedef boost::graph_traits<AdjacencyList>::adjacency_iterator AdjacencyIterator;
AdjacencyList::vertex_iterator i, end;
for (boost::tie(i, end) = boost::vertices(adjacency_list); i != end; i++) {
AdjacencyIterator ai, a_end;
boost::tie(ai, a_end) = boost::adjacent_vertices( *i, adjacency_list);
for (; ai != a_end; ai++) {
std::cout << *ai << "\t";
}
}
The Output I get are memory address in Hexademial number.
How can I get vertex indices and the edge weight?
You should access the property bundles, either using the graph's operator[] with the vertex/edge descriptor, or using the property map:
Using the operator[]
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
typedef boost::adjacency_list<boost::setS,boost::setS,boost::undirectedS, uint32_t, float> AdjacencyList;
typedef boost::graph_traits<AdjacencyList>::adjacency_iterator AdjacencyIterator;
int main() {
AdjacencyList adjacency_list;;
boost::add_edge(
boost::add_vertex(10, adjacency_list),
boost::add_vertex(20, adjacency_list),
1.5f,
adjacency_list
);
boost::add_edge(
boost::add_vertex(30, adjacency_list),
boost::add_vertex(40, adjacency_list),
2.5f,
adjacency_list
);
AdjacencyList::vertex_iterator i, end;
for (boost::tie(i, end) = boost::vertices(adjacency_list); i != end; i++) {
AdjacencyIterator ai, a_end;
boost::tie(ai, a_end) = boost::adjacent_vertices(*i, adjacency_list);
for (; ai != a_end; ai++) {
std::cout << adjacency_list[*ai] << "\t";
}
}
}
Output:
10 20 30 40
Using the property map:
boost::property_map<AdjacencyList, boost::vertex_bundle_t>::type pmap = boost::get(boost::vertex_bundle, adjacency_list);
Now you can use boost::get(pmap, vertex_descriptor1) to access the vertex property bundle
Related
I am a Boost (and C++) newbie, going through the graph library tutorial. I can create a graph and give it vertices and edges. I would like to use maximum cardinality matching in Boost to return a set of edges that form the maximum matching in the graph.
I have looked through max_cardinality_matching.hpp, but am not quite sure how to use it, or which functions to use, to return the maximum matching set of edges.
Here is my code so far:
#include <iostream>
#include <boost/graph/max_cardinality_matching.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
using namespace boost;
int main(int argc, const char * argv[]) {
// create a typedef for the Graph type
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
// Make convenient labels for the vertices
enum { A, B, C, D, E, F, N };
const int num_vertices = N;
// const char* name = "ABCDE";
// writing out the edges in the graph
typedef std::pair<int, int> Edge;
Edge edge_array[] =
{ Edge(A,B), Edge(B,C), Edge(C,D), Edge(D,E), Edge(E,F) };
// const int num_edges = sizeof(edge_array)/sizeof(edge_array[0]);
// declare a graph object and add the edges
Graph g(edge_array, edge_array + sizeof(edge_array) / sizeof(Edge), num_vertices);
// get the property map for vertex indices
// property_map<Graph, property type>
typedef property_map<Graph, vertex_index_t>::type IndexMap;
IndexMap index = get(vertex_index, g);
// Create an iterator for vertices
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
std::cout << "vertices(g) = ";
// Vertices returns a pair of vertex iterators
// The first iter points to the beginning of the vertices
// The second points past the end
std::pair<vertex_iter, vertex_iter> vp;
// vertices() returns the vertices in graph g
for (vp = vertices(g); vp.first != vp.second; ++vp.first)
std::cout << index[*vp.first] << " ";
std::cout << std::endl;
graph_traits<Graph>::edge_iterator ei, ei_end;
std::cout << "edges(g) = ";
// For each tuple of vertices (an edge), till the end of the edge list ...
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
// ... print out the source and target vertices in the edge
std::cout << "(" << index[source(*ei, g)] << "," << index[target(*ei, g)] << ") ";
std::cout << std::endl;
// Return the set of edges that form a maximum matching in graph g
return 0;
}
All you need to do is create read-write property map and pass it as second argument to
template <typename Graph, typename MateMap>
bool checked_edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate);
You can create ordinary std::map where key and value are vertex descriptors and adapts it by associative_property_map in order to use it with checked_edmonds_maximum_cardinality_matching. From this map you can read all edges which create maximum cardinality of your graph.
// Return the set of edges that form a maximum matching in graph g
typedef graph_traits<Graph>::vertex_descriptor VD;
std::map<VD, VD> match;
boost::associative_property_map< std::map<VD,VD> > mapAdapter(match);
bool rc = checked_edmonds_maximum_cardinality_matching(g,mapAdapter);
if (rc)
{
std::set<graph_traits<Graph>::edge_descriptor> edges;
for (auto& i : match)
{
std::pair<Graph::edge_descriptor,bool> e = boost::edge(i.first,i.second,g);
if (e.second)
edges.insert(e.first);
std::cout << i.first << " is matched to " << i.second << std::endl;
}
// print edges
for (auto& e : edges)
std::cout << "edge: " << e << std::endl;
}
As output you can see:
0 is matched to 1
1 is matched to 0
2 is matched to 3
3 is matched to 2
4 is matched to 5
5 is matched to 4
edge: (0,1)
edge: (2,3)
edge: (4,5)
So I'm posting this because I'm currently working on an algorithm project and might gonna use the boost library for building a graph from an input text file. So I have noticed that there is a descriptor for the vertex in a graph, but since I have a very large graph to be built, do I need to allocate a descriptor for every vertex in that graph? If I don't, can I traverse the whole graph after it's been built?
I'm a newbie to the boost library and this is a little emergent so if anybody can explain this I will be very grateful!
A vertex descriptor describes a vertex (in cheap, graph model independent way).
A graph model describes a graph.
Iterators
When you want to traverse a graph, you traverse the graph, using the iterators:
typedef boost::adjacency_list<> Graph;
typedef Graph::vertex_iterator Vit;
Vit begin, end;
boost::tie(begin, end) = vertices(g);
Dereferencing a valid iterator gives you the descriptor (same thing goes for edge iterators).
Simple demo:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
int main () {
typedef boost::adjacency_list<> Graph;
typedef Graph::vertex_iterator Vit;
Graph g(10);
add_edge(2,5,g);
add_edge(5,3,g);
add_edge(3,8,g);
Vit begin, end;
boost::tie(begin, end) = vertices(g);
for (Vit it = begin; it != end; ++it) {
unsigned edges = out_degree(*it, g);
if (edges)
std::cout << "vertex #" << *it << " has " << edges << " outgoing edge(s)\n";
}
}
Prints:
vertex #2 has 1 outgoing edge(s)
vertex #3 has 1 outgoing edge(s)
vertex #5 has 1 outgoing edge(s)
Graph Model With Node-Based Vertex Containers
Not all graph have integral vertex descriptors, so adding edges becomes more complicated, and printing them doesn't look so "friendly"
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
int main () {
typedef boost::adjacency_list<boost::setS, boost::listS/*, boost::undirectedS*/> Graph;
typedef Graph::vertex_iterator Vit;
Graph g(10);
Vit begin, end;
boost::tie(begin, end) = vertices(g);
{
std::vector<Graph::vertex_descriptor> vindex(begin, end);
add_edge(vindex[2], vindex[5], g);
add_edge(vindex[5], vindex[3], g);
add_edge(vindex[3], vindex[8], g);
}
for (Vit it = begin; it != end; ++it) {
unsigned edges = out_degree(*it, g);
if (edges)
std::cout << "vertex #" << *it << " has " << edges << " outgoing edge(s)\n";
}
}
Printing
vertex #0x994d00 has 1 outgoing edge(s)
vertex #0x994d70 has 1 outgoing edge(s)
vertex #0x994e50 has 1 outgoing edge(s)
Properties
In such cases, consider adding a property bundle.
This way, arbitrary application-specific information can be attached to model vertices (or edges, or graphs).
The main downside, in my opinion, of this is that there's no natural indexing for the properties, so looking up a graph entity by its (bundled) property could get bad performance (linear search) unless you keep an extra index outside of the graph manually.
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
struct VertexProperties {
std::string name;
VertexProperties(std::string name) : name(name) {}
};
int main () {
typedef boost::adjacency_list<boost::setS, boost::listS, boost::directedS, VertexProperties> Graph;
typedef Graph::vertex_iterator Vit;
Graph g;
add_vertex(VertexProperties ("zero"), g);
add_vertex(VertexProperties ("one"), g);
add_vertex(VertexProperties ("two"), g);
add_vertex(VertexProperties ("three"), g);
add_vertex(VertexProperties ("four"), g);
add_vertex(VertexProperties ("five"), g);
add_vertex(VertexProperties ("six"), g);
add_vertex(VertexProperties ("seven"), g);
add_vertex(VertexProperties ("eight"), g);
add_vertex(VertexProperties ("nine"), g);
Vit begin, end;
boost::tie(begin, end) = vertices(g);
{
std::vector<Graph::vertex_descriptor> vindex(begin, end);
add_edge(vindex[2], vindex[5], g);
add_edge(vindex[5], vindex[3], g);
add_edge(vindex[3], vindex[8], g);
}
for (Vit it = begin; it != end; ++it) {
unsigned edges = out_degree(*it, g);
if (edges)
std::cout << "vertex '" << g[*it].name << "' has " << edges << " outgoing edge(s)\n";
}
}
Prints
vertex 'two' has 1 outgoing edge(s)
vertex 'three' has 1 outgoing edge(s)
vertex 'five' has 1 outgoing edge(s)
Here's some example code to create a graph with bgl and iterate over the vertices. I would like to do this iteration in random order - in other words: the loop should manipulate every vertex, but the order of the vertices should be random for every call of the main function. How can I achieve this?
I experimented unsuccessfully with std::random_shuffle. I think there are different kinds of iterator concepts, but I don't understand the differences yet.
#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
// vertex struct to store some properties in vertices
struct Vertex {
std::string name;
};
int main(int,char*[]) {
// create a typedef for the graph type
typedef adjacency_list<vecS, vecS, undirectedS, Vertex> Graph;
// declare a graph object
Graph g(3);
// prepare iteration
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
std::pair<vertex_iter, vertex_iter> vp;
// add some property data to the vertices
vp = vertices(g);
g[*vp.first].name = "A";
g[*(++vp.first)].name = "B";
g[*(++vp.first)].name = "C";
// iterate over the vertices
for (vp = vertices(g); vp.first != vp.second; ++vp.first)
std::cout << g[*vp.first].name << " ";
std::cout << std::endl;
return 0;
}
Edit: Here's the solution I came up with thanks to the answer of #Jay.
#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <algorithm> // std::random_shuffle
#include <vector> // std::vector
#include <ctime> // std::time
#include <cstdlib> // std::rand, std::srand
using namespace boost;
// vertex struct to store some properties in vertices
struct Vertex {
std::string name;
};
// random number generator function
int myrandom (int i) {
return std::rand()%i;
}
int main(int,char*[]) {
// create a typedef for the graph type
typedef adjacency_list<vecS, vecS, undirectedS, Vertex> Graph;
// declare a graph object
Graph g(3);
// prepare iteration
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
std::pair<vertex_iter, vertex_iter> vp;
// add some property data to the vertices
vp = vertices(g);
g[*vp.first].name = "A";
g[*(++vp.first)].name = "B";
g[*(++vp.first)].name = "C";
// initialize pseudo random number generator
std::srand(unsigned (std::time(0)));
// create offset vector
std::vector<int> myvector;
for (int i=0; i<3; ++i) {
myvector.push_back(i);
}
// using myrandom to shuffle offset vector
std::random_shuffle(myvector.begin(), myvector.end(), myrandom);
// keep vp.first at the start
vp = vertices(g);
// iterate over the vertices effectively shuffled by the offset
vertex_iter dummy_iter;
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it) {
dummy_iter = vp.first + *it;
std::cout << g[*dummy_iter].name << " ";
}
std::cout << std::endl;
return 0;
}
I think the simplest thing to do is set up a random vector of indices, as outlined here. Then you can iterate the shuffled list and use it as an offset for your vertex iterator.
For example
vp = vertices(g); // Keep vp.first at the start
vertex_iter dummy_iter;
// Looping on a shuffled vector, values should be 0..N-1
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
{
dummy_iter = vp.first + *it;
Vertex* v = *dummy_iter;
...
To create a random number within a given range use the code below.
#include ctime and #include stdlib.h
int getNumberRange(int min, int max)
{
srand(static_cast<unsigned int>(time(0)));
// always call rand(); after srand() on visual vasic;
rand();
static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0);
return static_cast<int>(rand() * fraction * (max - min + 1) + min);
}
getNumberRange(1, 100); //picks number between 1 and 100
Every time you need a new number modify the range values (1, 100) and call the function again.
I am trying to write an algorithm to (greedily) find the chromatic number of a graph. For this I need to be able to query the adjacent vertices of a given vertex.
My function is the following:
int Network::greedy_colouring() {
// create an undirected graph with the vertices and edges of the first one
UndirectedGraph g;
copy_graph(network, g);
int vertices_amount = num_vertices(g);
// Assign the first color to first vertex
std::map<std::string, int> vertex_colouring;
vertex_pair_iterators vp = vertices(g);
vertex_colouring[g[*vp.first].name] = 0;
++vp.first; // start from second vertex
for (; vp.first != vp.second; ++vp.first)
vertex_colouring[g[*vp.first].name] = -1;
// A temporary array to store the available colors. True
// value of available[cr] would mean that the color cr is
// assigned to one of its adjacent vertices
bool available[vertices_amount];
for (int cr = 0; cr < vertices_amount; cr++)
available[cr] = false;
// Assign colors to remaining V-1 vertices
vp = vertices(g); // reset to beginning
++vp.first; // start from second vertex
for (; vp.first != vp.second; ++vp.first) {
// Process all adjacent vertices and flag their colors
// as unavailable
for (std::pair<adjacency_it, adjacency_it> neighbours = boost::adjacent_vertices(g[*vp.first], g);
neighbours.first != neighbours.second; ++neighbours.first)
if (vertex_colouring[g[*neighbours.first].name] != -1)
available[vertex_colouring[g[*neighbours.first].name]] = true;
// Find the first available color
int cr;
for (cr = 0; cr < vertices_amount; cr++)
if (available[cr] == false)
break;
vertex_colouring[g[*vp.first].name] = cr; // Assign the found color
// Reset the values back to false for the next iteration
neighbours = boost::adjacent_vertices(g[*vp.first], g); // reset to beginning
for (; neighbours.first != neighbours.second; ++neighbours.first)
if (vertex_colouring[g[*neighbours.first].name] != -1)
available[vertex_colouring[g[*neighbours.first].name]] = false;
}
// print the result and find colour number
unsigned colour_number = 0;
for (std::map<std::string, int>::iterator it = vertex_colouring.begin(); it != vertex_colouring.end(); ++it) {
std::cout << "Vertex " << it->first << " ---> Color " << it->second << std::endl;
if (it->second > colour_number)
colour_number = it->second;
}
return colour_number;
}
The error I get is related to the call to:
std::pair<adjacency_it, adjacency_it> neighbours = boost::adjacent_vertices(g[*vp.first],g)
Which gives the following compile error: "error: no matching function for call to ‘boost::adjacency_iterator ... " (partial copy).
Commenting out the code related to the function adjacency lets it compile, so I am sure that this is the problem code.
Some typedefs that are being used in the function:
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge > Graph;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge > UndirectedGraph;
typedef std::pair<Vertex ,Vertex > vert_p;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
typedef boost::graph_traits<Graph>::in_edge_iterator in_edge_it;
typedef boost::graph_traits<Graph>::vertex_iterator vertex_iter;
typedef boost::graph_traits<Graph>::edge_iterator edge_iter;
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
typedef std::pair<vertex_iter, vertex_iter> vertex_pair_iterators;
typedef std::pair<in_edge_it, in_edge_it> edge_pair_iterators;
typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_it;
Can anyone give me a clue what I am doing wrong?
Two issues:
the first argument needs to be a vertex descriptor, not the property bundle. Change
boost::adjacent_vertices(g[*vp.first], g)
into
boost::adjacent_vertices(*vp.first, g)
the return type is std::pair<adjacency_iterator, adjacency_iterator>. However, you defined adjacency_iterator as
typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_it;
when it needs to be
typedef boost::graph_traits<UndirectedGraph>::adjacency_iterator adjacency_it;
Further notes:
It's easier to work with separate iterators instead of vp.first and vp.second (use boost::tie to assign both at once)
You have a "poisonous" unsigned value in your comparison, write it explicitly as
if(it->second > static_cast<int>(colour_number))
Or review the logic with possible -1 values in the map.
it's likely very inefficient to keep the colour map indexed by Vertex::name (which is a string). You should consider indexing by vertex_descriptor.
Now, since your vertex model uses vecS for the VertexContainer, you could actually use the fact that this descriptor is an integral index in the range [0, num_vertices(g)).
Therefore you can replace the map<> (which has bad memory locality) with a vector<int> (where the vertex descriptor is the vector index).
If you want to support other graph models, you can let the caller pass in an IndexMap that maps vertex-descriptor to similar consecutive indices. Lots of algorithms in the BGL use this approach.
Obviously, bool[] could (should) be std::bitset or even std::vector<bool>. Boost has the dynamic_bitset which is probably best here.
(I'd need to understand your algorithm a lot better. Perhaps a set of "taken" colour would be even better. And implemented as an unsorted contiguous collection for speed, unless you anticipate the number of colour to get big enough that an ordered/hash lookup would be faster (?!).
Always make your code selfcontained:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <iostream>
struct Vertex {
std::string name;
};
struct Edge {
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge > Graph;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge > UndirectedGraph;
Graph network;
int greedy_colouring() {
using namespace boost;
typedef boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
static_assert(is_integral<vertex_descriptor>::value, "IndexMap not provided yet TODO");
typedef boost::graph_traits<UndirectedGraph>::vertex_iterator vertex_iter;
typedef boost::graph_traits<UndirectedGraph>::adjacency_iterator adjacency_it;
// create an undirected graph with the vertices and edges of the first one
UndirectedGraph g;
copy_graph(network, g);
vertex_iter vit, vend;
tie(vit, vend) = vertices(g);
size_t const vertices_amount = num_vertices(g);
std::vector<int> vertex_colouring(vertices_amount, -1);
vertex_colouring[*vit] = 0; // Assign the first color to first vertex
// A temporary array to store the available colors.
// - available[cr]: assigned to one of its adjacent vertices
std::vector<bool> available(vertices_amount, false);
for (++vit; vit!=vend; ++vit)
{
// Process all adjacent vertices and flag their colors as unavailable
adjacency_it neighbour, neighbour_end;
for (tie(neighbour, neighbour_end) = adjacent_vertices(*vit, g); neighbour != neighbour_end; ++neighbour)
if (vertex_colouring[*neighbour] != -1)
available[vertex_colouring[*neighbour]] = true;
// Find the first available color
vertex_colouring[*vit] = distance(available.begin(), std::find(available.begin(), available.end(), false));
// Reset the values back to false for the next iteration
for (tie(neighbour, neighbour_end) = adjacent_vertices(*vit, g); neighbour != neighbour_end; ++neighbour)
if (vertex_colouring[*neighbour] != -1)
available[vertex_colouring[*neighbour]] = false;
}
// print the result and find colour number
for (vertex_descriptor v = 0; v < vertices_amount; ++v)
std::cout << "Vertex " << v << " ---> Color " << vertex_colouring[v] << std::endl;
return *std::max_element(vertex_colouring.begin(), vertex_colouring.end());
}
int main() { }
I have a set of edges E, and I want to know if I can safely remove edge i in E, meaning if I remove it from the graph, the graph should still be connected.
In my understanding that implies that edge i, has to lie on a circle.
The output should be a list of indices of all edges I can't remove.
The problem:
My different solutions seem to do the right thing, but are far too slow (inefficient).
One of my solutions was:
1. Loop through all edges i in E
2. Loop through all edges x in V
3. Add edge x to the graph (excluding edge i) until nodes of i are connected or end reached
4. If no connection possible, edge is not removable and added to the list
This way was way too slow.
I then decided to rewrite my code and use breadth-first-search to look if another path is possible without edge i.
I thought it would be performant enough, but it seems it's not. Either I have implemented in a very bad way or that's also the wrong algorithm for this task.
Here is the algorithm in the C++ code I have (removed some not important parts):
struct connection {
int a, b;
};
void expand(int x, connection *&arr, std::set<int> &exp, int size) {
for (int i = 0; i < size; i++) {
if (x == arr[i].a) {
exp.insert(arr[i].b);
}
else if (x == arr[i].b) {
exp.insert(arr[i].a);
}
}
return;
}
// recursive breadth-first-seach
bool BFSr(std::set<int> &group, std::set<int> &visited, int goal, connection *&arr, int size) {
if (group.empty()) return false;
if (group.find(goal) != group.end()) return true;
std::set<int> tempa;
for (std::set<int>::iterator it = group.begin(); it != group.end(); ++it) {
expand(*it, arr, tempa size);
}
for (std::set<int>::iterator it = visited.begin(); it != visited.end(); ++it) {
tempa.erase(*it);
}
tempb = visited;
tempb.insert(group.begin(), group.end());
return BFSr(tempa, tempb, goal, arr, size);
}
bool BFS(int start, int goal, connection *&arr, int size) {
std::set<int> tempa;
std::set<int> tempb;
tempa.insert(start);
return BFSr(tempa, tempb, goal, arr, size);
}
int main()
{
connection *arr = new connection[m];
connection *con = new connection[m - 1];
// fill arr with connections arr.a < arr.b ....
for (int j = 0; j < (m - 1); j++) {
con[j] = arr[j + 1];
}
// 1. edge for performance reasons extra
if (!BFS(arr[0].a, arr[0].b, con, (m - 1))) {
// connection is important therefore add to list
printf(" %d", 1);
}
// Look if nodes still connected after removing connection
for (int s = 1; s < m; s++) {
con[s - 1] = arr[s - 1];
if (!BFS(arr[s].a, arr[s].b, con, (m-1))) {
// connection is important therefore add to list
printf(" %d", s + 1);
}
}
printf("\n");
free(arr);
free(con);
return 0;
}
Do you know any solutions for me to make it faster, or do you know a better algorithm for my problem?
An edge whose deletion disconnects two connected components is called a bridge and there are linear-time algorithms for finding all the bridges in a graph (usually based on depth-first search). The Wikipedia article lists one of them (due to Tarjan) as an example. This paper also gives a simple algorithm for listing all the bridges in a graph and seems to be a bit simpler than Tarjan's algorithm.
Hope this helps!
Here is another version of your algorithm (I guess you will get industry standard optimization implementation of graph and various algorithm for free):
I am referring to this image as graph model.
Gist (from this post)
find articulation points
all points with single out-edge are
articulation points (boost graph won't return these)- these edges
are automatically bridging edges
for each articulation point-
loop over each outedge, if outedge already not bridging edge- then
remove the edge and check for graph components and add the edge back
again
At the end it will print Edge(a,g) connects components in graph
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/biconnected_components.hpp>
#include <boost/graph/connected_components.hpp>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
typedef boost::adjacency_list <boost::vecS, boost::vecS, boost::undirectedS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef boost::graph_traits<Graph>::edge_descriptor edge_t;
// reference:
// http://lists.boost.org/boost-users/2005/08/13098.php
//
struct edge_t_hasher
{
std::size_t operator()(const edge_t& e) const
{
auto prop = e.get_property();
std::hash<decltype(prop)> hasher;
return hasher(prop);
}
};
typedef std::unordered_set<edge_t, edge_t_hasher> UnorderedBoostEdgeSet;
Graph getGraph()
{
Graph g;
vertex_t aVtx = boost::add_vertex(g);
vertex_t bVtx = boost::add_vertex(g);
vertex_t cVtx = boost::add_vertex(g);
vertex_t dVtx = boost::add_vertex(g);
vertex_t eVtx = boost::add_vertex(g);
vertex_t fVtx = boost::add_vertex(g);
vertex_t gVtx = boost::add_vertex(g);
vertex_t hVtx = boost::add_vertex(g);
vertex_t iVtx = boost::add_vertex(g);
boost::add_edge(dVtx, cVtx, g);
boost::add_edge(dVtx, bVtx, g);
boost::add_edge(cVtx, bVtx, g);
boost::add_edge(aVtx, bVtx, g);
boost::add_edge(bVtx, eVtx, g);
boost::add_edge(eVtx, fVtx, g);
boost::add_edge(aVtx, fVtx, g);
boost::add_edge(aVtx, gVtx, g);// edge connecting components
boost::add_edge(gVtx, iVtx, g);
boost::add_edge(gVtx, hVtx, g);
boost::add_edge(hVtx, iVtx, g);
return g;
}
UnorderedBoostEdgeSet bridgingEdgesForGraph(const Graph& graph)
{
UnorderedBoostEdgeSet bridgeEdges;
std::unordered_set<vertex_t> articulationVertices;
boost::articulation_points(graph, std::inserter(articulationVertices, articulationVertices.end()));
// add all the single connected vertices to the articulation vertices
auto vtxIters = boost::vertices(graph);
for (auto it = vtxIters.first, end = vtxIters.second; it != end; ++it)
{
if (boost::out_degree(*it, graph) == 1)
bridgeEdges.insert(*(boost::out_edges(*it, graph).first));
}
std::vector<vertex_t> componentsInGraph(boost::num_vertices(graph));
int numComponentsInGraph = boost::connected_components(graph, &componentsInGraph[0]);
// for each articulation vertex now get edges and check if removing that
// edge causes graph change in connected components
//
// copy the graph- so we can iterate over the outeges of vertices
// we will be fiddling with the copy- since the vtx descriptors are
// ints- they stay same across copy and removing edge operation
auto graph2 = graph;
for (auto vtx : articulationVertices)
{
auto outEdges = boost::out_edges(vtx, graph);
for (auto it = outEdges.first, end = outEdges.second; it != end; ++it)
{
auto edge = *it;
if (bridgeEdges.find(edge) != bridgeEdges.end())
continue;
// map this edge to graph2 edge- for removal and eventual addition
auto src = boost::source(edge, graph);
auto tgt = boost::target(edge, graph);
auto edge2 = boost::edge(src, tgt, graph2).first;
boost::remove_edge(edge2, graph2);
std::vector<vertex_t> componentsInGraph2(boost::num_vertices(graph2));
int numComponentsInGraph2 = boost::connected_components(graph2, &componentsInGraph2[0]);
// bridging edge- graph #components changed
if (numComponentsInGraph != numComponentsInGraph2)
bridgeEdges.insert(edge);
// add the edge back to graph2
boost::add_edge(src, tgt, graph2);
}
}
return bridgeEdges;
}
int main()
{
const Graph& graph = getGraph();
const auto& bridgingEdges = bridgingEdgesForGraph(graph);
const char* array = {"ABCDEFGHI"};
for (auto edge : bridgingEdges)
{
std::cout << "Edge(" << array[boost::source(edge, graph)] << ", " << array[boost::target(edge, graph)]
<< ") is a bridging edge" << std::endl;
}
return 0;
}
Meanwhile I found out how those special edges are called: Bridges.
And therefore I found a site giving an DFS algorithm for finding all bridges.
It's fast enough for my purposes.
DFS algorithm for finding Bridges in a undirected Graph
Thank you Sarang, your post made me find the correct search words for the site.