How to determine if a path exists between 2 vertices in BGL - c++

I want to use the Boost Graph Library to decide if there is a path between 2 nodes on an directed unweighted graph.
Therefore I try to use either Breath-First-Search or Dijkstra but I got confused by all these parameter lists.
What is the simplest way to create a function like this:
bool isPath(src,dest);
with BGL?

BFS/DFS is the simplest way. I'll sketch up DFS solution because it's less memory hungry.
Presuming you have adjacency matrix adj of size N x N (N being number of vertices in a graph) with:
1 in adj[i][j] if you have edge going from i vertex to j vertex,
0 otherwise.
In that case you could have something like this:
// doing DFS...
bool isPath(int src, int dest) {
bool visited[N] = {false};
visited[src] = true;
std::stack<int> next;
next.push(src);
while(!next.empty()) {
int cv = next.top();
next.pop();
for (int nv = 0; nv < N; ++nv) {
if (!visited[nv] && adj[cv][nv] == 1) {
visited[nv] = true;
next.push(nv);
}
}
}
// dest was reached from src?
return visited[dest];
}

Related

How to do a DFS on a tree? (not necessarily binary)

I have a tree of n nodes (labeled 0 to n). I used two vectors to hold the edge information.
typedef std::vector<std::vector<int>> graph;
The input is n-1 edges in the form:
0 1
1 2
2 3
and so on
I'm told node 0 is always the root node.
I scan the edges using the following:
for (int i = 0; i < n-1; i++) {
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a); // the second approach doesn't use this line
}
This is my simple dfs:
void dfs(graph &g, int v) {
std::vector<int> visited; // I don't use a visited array for the second approach
for (int i = 0; i < g.size(); i++) {
visited.push_back(0);
}
std::stack<int> s;
std::set<int> t;
s.push(v);
while (!s.empty()) {
int i = s.top(); s.pop();
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (!visited[i]) {
visited[i] = true;
s.push(g[v][i]);
}
}
}
}
For example say we have 4 nodes and the following edges:
0 1
0 2
3 2
2 4
Say that I'm interested in the sub tree starting at 2. The above approach won't work because I'm inserting undirected edges 0 2 and 2 0. So when I start my dfs at 2 I add node 0 to my stack which is wrong.
I tried another approach of only inserting the edges given only but that also didn't work because in the example I would've inserted 3 2 which is an edge from 3 to node 2 and so when I start my dfs at node 2 I won't be able to reach node 3.
I feel like the problem is simple and I'm missing some big idea!
Since your graph is a rooted tree, you can do the following preprocessing.
Start a DFS from root (vertex #0);
For each vertex u, store its parent v. It means that if you travel alongside shortest path from root to u, the second-to-last vertex on this path will be v. Notice that in any tree there is exactly one shortest path from one vertex to another. Let's say that you have an array parent such that parent[u] = v according to above definition, and parent[0] = -1.
You can compute parent array by noticing, that if you do s.push(g[v][i]), then v is the parent of i (otherwise you would have visited i first);
Since parent[v] is the previous vertex on shortest path from global root (vertex 0), it is also the previous vertex on shortest path from any vertex x, which contains v in its subtree.
Now when you want to DFS over subtree of vertex u, you do DFS as you do it now, but do not visit the parent of any vertex. Say, if you want to do s.push(v), while parent[u] = v, do not do it. This way you will never leave the subtree of u.
Actually, knowing parent, you can get rid of your visited array. When you "do stuff" with vertex v, the only neighbour of v that is already visited is parent[v]. This property does not depend on the initial vertex, whose subtree you want to traverse. The DFS code would look like this (assuming you've done preprocessing to obtain parent:
void dfs(graph &g, vector<int> &parent, int v) {
std::stack<int> s;
s.push(v);
while (!s.empty()) {
int v = s.top(); s.pop(); // By the way, you have mistake here: int i = s.top().
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (parent[v] != g[v][i]) {
s.push(g[v][i]);
}
}
}
}
PS This approach is somehow similar to your second approach: it only treats edges that go from root to subtree. But it does not have the flaw, such as in your example with "3 2" being the wrong direction, because you infer direction algorithmically by doing DFS from root.

Depth First Search: Formatting output?

If I have the following graph:
Marisa Mariah
\ /
Mary---Maria---Marian---Maryanne
|
Marley--Marla
How should be Depth First Search function be implemented such that I get the output if "Mary" is my start point ?
Mary
Maria
Marisa
Mariah
Marian
Maryanne
Marla
Merley
I do realize that the number of spaces equal to depth of the vertex( name ) but I don't how to code that. Following is my function:
void DFS(Graph g, Vertex origin)
{
stack<Vertex> vertexStack;
vertexStack.push(origin);
Vertex currentVertex;
int currentDepth = 0;
while( ! vertexStack.empty() )
{
currentVertex = vertexStack.top();
vertexStack.pop();
if(currentVertex.visited == false)
{
cout << currentVertex.name << endl;
currentVertex.visited = true;
for(int i = 0; i < currentVertex.adjacencyList.size(); i++)
vertexStack.push(currentVertex.adjacencyList[i]);
}
}
}
Thanks for any help !
Just store the node and its depth your stack:
std::stack<std::pair<Vertex, int>> vertexStack;
vertexStack.push(std::make_pair(origin, 0));
// ...
std::pair<Vertex, int> current = vertexStack.top();
Vertex currentVertex = current.first;
int depth = current.second;
If you want to get fancy, you can extra the two values using std::tie():
Vertex currentVertex;
int depth;
std::tie(currentVertex, depth) = vertexStack.top();
With knowing the depth you'd just indent the output appropriately.
The current size of your stack is, BTW, unnecessarily deep! I think for a complete graph it may contain O(N * N) elements (more precisely, (N-1) * (N-2)). The problem is that you push many nodes which may get visited.
Assuming using an implicit stack (i.e., recursion) is out of question (it won't work for large graphs as you may get a stack overflow), the proper way to implement a depth first search would be:
push the current node and edge on the stack
mark the top node visited and print it, using the stack depth as indentation
if there is no node
if the top nodes contains an unvisited node (increment the edge iterator until such a node is found) go to 1.
otherwise (the edge iterator reached the end) remove the top node and go to 3.
In code this would look something like this:
std::stack<std::pair<Node, int> > stack;
stack.push(std::make_pair(origin, 0));
while (!stack.empty()) {
std::pair<Node, int>& top = stack.top();
for (; top.second < top.first.adjacencyList.size(); ++top.second) {
Node& adjacent = top.first.adjacencyList[top.second];
if (!adjacent.visited) {
adjacent.visted = true;
stack.push(std::make_pair(adjacent, 0));
print(adjacent, stack.size());
break;
}
}
if (stack.top().first.adjacencyList.size() == stack.top().second) {
stack.pop();
}
}
Let Rep(Tree) be the representation of the tree Tree. Then, Rep(Tree) looks like this:
Root
<Rep(Subtree rooted at node 1)>
<Rep(Subtree rooted at node 2)>
.
.
.
So, have your dfs function simply return the representation of the subtree rooted at that node and modify this value accordingly. Alternately, just tell every dfs call to print the representation of the tree rooted at that node but pass it the current depth. Here's an example implementation of the latter approach.
void PrintRep(const Graph& g, Vertex current, int depth)
{
cout << std::string(' ', 2*depth) << current.name << endl;
current.visited = true;
for(int i = 0; i < current.adjacencyList.size(); i++)
if(current.adjacencyList[i].visited == false)
PrintRep(g, current.adjacencyList[i], depth+1);
}
You would call this function with with your origin and depth 0 like this:
PrintRep(g, origin, 0);

Dijkstra's Algorithm - Initializing Node Distances

I have an assignment to use Dijkstra's shortest path algorithm for a simple network simulation. There's one part of the coding implementation that I don't understand and it's giving me grief.
I searched around on stack overflow and found many helpful questions about Dijkstra's, but none with my specific question. I apologize if I didn't research thoroughly enough.
I'm using this pseudocode from Mark Allen Weiss's Data Structures and Algorithm Analysis in C++:
void Graph::dijkstra( Vertex s)
{
for each Vertex v
{
v.dist = INFINITY;
v.known = false;
}
s.dist = 0;
while( there is an unknown distance vertex )
{
Vertex v = smallest unknown distance vertex;
v.known = true;
for each Vertex w adjacent to v
{
if (!w.known)
{
int cvw = cost of edge from v to w;
if(v.dist + cvw < w.dist)
{
//update w
decrease(w.dist to v.dist + cvw);
w.path = v;
}
}
}
}
and my implementation seems to work aside from the last if statement.
if(v.dist + cvw < w.dist)
My code will never go into what's underneath because the distance for every node is initialized to (essentially) infinity and the algorithm never seems to change the distance. Therefore the left side of the comparison is never smaller than the right side. How am I misunderstanding this?
Here is my (messy) code:
class Vertex
{
private:
int id;
unordered_map < Vertex*, int > edges;
int load_factor;
int distance;
bool known;
public:
//getters and setters
};
void dijkstra(Vertex starting_vertex)
{
for (int i = 0; i < vertices.size(); i++)
{
//my program initially stores vertices in the vertex in spot (id - 1).
if (vertices[i].get_id() == starting_vertex.get_id())
{
vertices[i].set_distance(0);
vertices[i].set_known(true);
}
else
{
vertices[i].set_distance(10000000);
vertices[i].set_known(false);
}
}
for (int i = 0; i < vertices.size(); i++)
{
//while there is an unknown distance vertex
if (vertices[i].is_known() == false)
{
vertices[i].set_known(true);
//for every vertex adjacent to this vertex
for (pair<Vertex*, int> edge : vertices[i].get_edges())
{
//if the vertex isn't known
if (edge.first->is_known() == false)
{
//calculate the weight using Adam's note on dijkstra's algorithm
int weight = edge.second * edge.first->get_load_factor();
if (vertices[i].get_distance() + weight < edge.first->get_distance())
//this is my problem line. The left side is never smaller than the right.
{
edge.first->set_distance(vertices[i].get_distance() + weight);
path.add_vertex(edge.first);
}
}
}
}
}
}
Thank you!
You are missing out this step:
Vertex v = smallest unknown distance vertex;
and instead looping through all vertices.
The distance to the starting vertex is initialized to 0 so if you implement this part of the algorithm and pick the v with the smallest distance that is not "known" you will start with the starting vertex and the if should work.
Replace:
for (int i = 0; i < vertices.size(); i++)
{
//while there is an unknown distance vertex
if (vertices[i].is_known() == false)
{
...
}
}
With something like:
while(countNumberOfUnknownVertices(vertices) > 0)
{
Vertex& v = findUnknownVertexWithSmallestDistance(vertices);
...
}
You missed two important parts of Dijkstra's Algorithm.
In implementing
while( there is an unknown distance vertex )
{
Vertex v = smallest unknown distance vertex;
you set v to the first unknown vertex you come to. It's supposed to be, of all the unknown vertices, the one whose distance is least.
The other misstep is that, instead of making one pass over the vertices and doing some work on each unknown one you find, you need to search again after doing the work.
For example, if on one iteration you expand outward from vertex 5, that may make vertex 3 the new unknown vertex with least distance. You can't just continue the search from 5.
The search for the least-distance unknown vertex is going to be slow unless you develop some data structure (a Heap, perhaps) to make that search fast. Go ahead and do a linear search for now. Dijkstra's Algorithm will still work, but it'll take time O(N^2). You should be able to get it down to at least O(N log N).

Create Minimum Spanning Tree from Adjacency Matrix using Prims Algorithm

I want to implement Prims algorithm to find the minimal spanning tree of a graph. I have written some code to start with what I think is the way to do it, but Im kind of stuck on how to complete this.
Right now, I have a matrix stored in matrix[i][j], which is stored as a vector>. I have also a list of IP address stored in the variable ip. (This becomes the labels of each column/row in the graph)
int n = 0;
for(int i = 0; i<ip.size();i++) // column
{
for(int j = ip.size()-1; j>n;j--)
{
if(matrix[i][j] > 0)
{
edgef test;
test.ip1 = ip[i];
test.ip2 = ip[j];
test.w = matrix[i][j];
add(test);
}
}
n++;
}
At the moment, this code will look into one column, and add all the weights associated with that column to a binary min heap. What I want to do is, dequeue an item from the heap and store it somewhere if it is the minimum edge weight.
void entry::add(edgef x)
{
int current, temp;
current = heap.size();
heap.push_back(x);
if(heap.size() > 1)
{
while(heap[current].w < heap[current/2].w) // if child is less than parent, min heap style
{
edgef temp = heap[current/2]; // swap
heap[current/2] = heap[current];
heap[current] = temp;
current = current/2;
}
}
}

Creating random undirected graph in C++

The issue is I need to create a random undirected graph to test the benchmark of Dijkstra's algorithm using an array and heap to store vertices. AFAIK a heap implementation shall be faster than an array when running on sparse and average graphs, however when it comes to dense graphs, the heap should became less efficient than an array.
I tried to write code that will produce a graph based on the input - number of vertices and total number of edges (maximum number of edges in undirected graph is n(n-1)/2).
On the entrance I divide the total number of edges by the number of vertices so that I have a const number of edges coming out from every single vertex. The graph is represented by an adjacency list. Here is what I came up with:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <set>
#define MAX 1000
#define MIN 1
class Vertex
{
public:
int Number;
int Distance;
Vertex(void);
Vertex(int, int);
~Vertex(void);
};
Vertex::Vertex(void)
{
Number = 0;
Distance = 0;
}
Vertex::Vertex(int C, int D)
{
Number = C;
Distance = D;
}
Vertex::~Vertex(void)
{
}
int main()
{
int VertexNumber, EdgeNumber;
while(scanf("%d %d", &VertexNumber, &EdgeNumber) > 0)
{
int EdgesFromVertex = (EdgeNumber/VertexNumber);
std::list<Vertex>* Graph = new std::list<Vertex> [VertexNumber];
srand(time(NULL));
int Distance, Neighbour;
bool Exist, First;
std::set<std::pair<int, int>> Added;
for(int i = 0; i < VertexNumber; i++)
{
for(int j = 0; j < EdgesFromVertex; j++)
{
First = true;
Exist = true;
while(First || Exist)
{
Neighbour = rand() % (VertexNumber - 1) + 0;
if(!Added.count(std::pair<int, int>(i, Neighbour)))
{
Added.insert(std::pair<int, int>(i, Neighbour));
Exist = false;
}
First = false;
}
}
First = true;
std::set<std::pair<int, int>>::iterator next = Added.begin();
for(std::set<std::pair<int, int>>::iterator it = Added.begin(); it != Added.end();)
{
if(!First)
Added.erase(next);
Distance = rand() % MAX + MIN;
Graph[it->first].push_back(Vertex(it->second, Distance));
Graph[it->second].push_back(Vertex(it->first, Distance));
std::set<std::pair<int, int>>::iterator next = it;
First = false;
}
}
// Dijkstra's implementation
}
return 0;
}
I get an error:
set iterator not dereferencable" when trying to create graph from set data.
I know it has something to do with erasing set elements on the fly, however I need to erase them asap to diminish memory usage.
Maybe there's a better way to create some undirectioned graph? Mine is pretty raw, but that's the best I came up with. I was thinking about making a directed graph which is easier task, but it doesn't ensure that every two vertices will be connected.
I would be grateful for any tips and solutions!
Piotry had basically the same idea I did, but he left off a step.
Only read half the matrix, and ignore you diagonal for writing values to. If you always want a node to have an edge to itself, add a one at the diagonal. If you always do not want a node to have an edge to itself, leave it as a zero.
You can read the other half of your matrix for a second graph for testing your implementation.
Look at the description of std::set::erase :
Iterator validity
Iterators, pointers and references referring to elements removed by
the function are invalidated.
All other iterators, pointers and
references keep their validity.
In your code, if next is equal to it, and you erase element of std::set by next, you can't use it. In this case you must (at least) change it and only after this keep using of it.