Finding the shortest paths of a directed graph C++ - c++

Over the last week, I have implemented a Digraph by parsing an input file. The graph is guaranteed to have no cycles. I have successfully created the graph, used methods to return the number of vertices and edges, and performed a topological sort of the graph. The graph is composed of different major courses and their prereqs. Here is my graph setup:
class vertex{
public:
typedef std::pair<int, vertex*> ve;
std::vector<ve> adjacency;
std::string course;
vertex(std::string c){
course = c;
}
};
class Digraph{
public:
typedef std::map<std::string, vertex *> vmap;
vmap work;
typedef std::unordered_set<vertex*> marksSet;
marksSet marks;
typedef std::deque<vertex*> stack;
stack topo;
void dfs(vertex* vcur);
void addVertex(std::string&);
void addEdge(std::string& from, std::string& to, int cost);
int getNumVertices();
int getNumEdges();
void getTopoSort();
};
The implementation
//function to add vertex's to the graph
void Digraph::addVertex(std::string& course){
vmap::iterator iter = work.begin();
iter = work.find(course);
if(iter == work.end()){
vertex *v;
v = new vertex(course);
work[course] = v;
return;
}
}
//method to add edges to the graph
void Digraph::addEdge(std::string& from, std::string& to, int cost){
vertex *f = (work.find(from)->second);
vertex *t = (work.find(to)->second);
std::pair<int, vertex *> edge = std::make_pair(cost, t);
f->adjacency.push_back(edge);
}
//method to return the number of vertices in the graph
int Digraph::getNumVertices(){
return work.size();
}
//method to return the number of edges in the graph
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count;
}
//recursive function used by the topological sort method
void Digraph::dfs(vertex* vcur) {
marks.insert(vcur);
for (const auto & adj : vcur->adjacency) {
vertex* suc = adj.second;
if (marks.find(suc) == marks.end()) {
this->dfs(suc);
}
}
topo.push_front(vcur);
}
//method to calculate and print out a topological sort of the graph
void Digraph::getTopoSort(){
marks.clear();
topo.clear();
for (const auto & v : work) {
if (marks.find(v.second) == marks.end()) {
this->dfs(v.second);
}
}
// Display it
for (const auto v : topo) {
std::cout << v->course << "\n";
}
}
For the last part of my implementation, I have been trying to do 2 things. Find the shortest path from the first vertex to every other vertices, and also find the shortest path that visits every vertex and returns to the first one. I am completely lost on this implementation. I assumed from reading I need to use Dijkstra's algorithm to implement this. I have been trying for the last 3 days to no avail. Did i set up my digraph in a bad way to implement these steps? Any guidance is appreciated.

The fact that there are no cycles makes the problem much simpler. Finding the shortest paths and a minimal "grand tour" are O(n).
Implement Dijkstra and run it, without a "destination" node; just keep going until all nodes have been visited. Once every node has been marked (with its distance to the root), you can start at any node and follow the shortest (and only) path back to the root by always stepping to the only neighbor whose distance is less than this one. If you want, you can construct these paths quite easily as you go, and mark each node with the full path back to the root, but copying those paths can push the cost to O(n2) if you're not careful.
And once all the nodes are marked, you can construct a minimal grand tour. Start at the root; when you visit a node, iterate over its unvisited neighbors (i.e. all but the one you just came from), visiting each, then go back the one you came from. (I can put this with more mathematical rigor, or give an example, if you like.)

Related

DFS traversal and cycle in directed graph

I have a directed graph. Initially, all nodes are assumed to be unvisited and flag is -1 in vector<int>flag. Now we start from a source node & push into stack<int>s and make flag[source]=0 . Now I do DFS traversal & push nodes if(flag[node]==-1)& make flag[node]=0. if all the DFS directed links are visited I pop the element of the stack and mark it flag[s.top()]=1; while pushing if we encounter a node with flag[nodes]==0, the cycle is detected and i do an increment in int final variable;`
you can see in my code, I am storing DFS traversal in a temp vector, which I think is garbage, how can I directly pass these connected nodes directly to check the flag and detect the cycle. currently my code works but fails for larger input. kindly looking for help.
#include<iostream>
#include<vector>
#include<stack>
#include<map>
using namespace std;
int mx=1e5+5;
vector<bool>vist(mx);
vector<vector<int>>Graph(mx);
void dfs(int node,vector<int>&dfs_vec){
vist[node]=true;
dfs_vec.push_back(node);
for(int neigh: Graph[node]){
if(!vist[neigh]){
dfs(neigh,dfs_vec);
}
}
}
//my temp vector is in while loop of main.
int main(){
int num_vertex;int num_edge;
cin>>num_vertex>>num_edge;
int u,v;
for(int i=0;i<num_edge;i++){
cin>>u>>v;
Graph[u].push_back(v);
}
vector<int>flag(num_vertex+1,-1);
stack<int>s;
int source=1;
s.push(source);
flag[source]=0;
int final=0;
while(!s.empty()){
int x=s.top();
vector<int>temp;
dfs(Graph[x][0],temp);
for(auto y:temp){
if(flag[y]==-1){
s.push(y);
flag[y]=0;
}
else if(flag[y]==0){
final++;
}
}
flag[s.top()]=1;
s.pop();
vist.clear();
vist.resize(mx);
}
if(final>0){
std::cout<<"Graph is cyclic";
}
else{
std::cout<<"Graph is not cyclic";
}
}
It is important to minimize the parameters in the signature of a recursive function if you want to handle large datasets. Each call requires the parameters to be kept on the stack, a fairly limited resource.
To minimize the parameters, use a method on a class which stores just one copy of the parameter data as an attribute whenever possible. For DFS, everything except the index of the currently visited node can be moved out of the parameter list.
Here is a straight forward implementation of DFS which I have used successfully on graphs containing hundreds of thousands of vertices.
void cPathFinder::depthRecurse(
int v )
{
visitor(v);
// remember this node has been visited
myPath[v] = 1;
// look for new adjacent nodes
for (int w : adjacent(v))
if (!myPath[w])
{
// search from new node
depthRecurse(w, visitor);
}
}
FYI here is brief discussion of some of the issues to think about when designing a class to implement graph theory algorithms. https://github.com/JamesBremner/PathFinder2/wiki/cGraph-Class-Design

Struct parent node refers to itself (infinite loop)

I'm implementing a Dijkstra's algorithm. The code I've written works in terms of finding the shortest path. However, the problem is when I try to save the path.
Just a heads up: I'm using Stanford's library , so some things might be different (e.g. Set has contains method) but functionality is mostly identical to standard libraries.
Vector<Loc> shortestPath(Loc start, Loc end, Grid<double>& world,
double costFn(Loc from, Loc to, Grid<double>& world)) {
Vector<Loc> vec;
Map<Loc, double> distanceMap;
TrailblazerPQueue<Loc> queue; // priority queue with decrease key method
Set<Loc> greenNodes;
Set<Loc> yellowNodes;
colorCell(world, start, YELLOW);
queue.enqueue(start, 0);
while(!queue.isEmpty()) {
Loc currNode = queue.dequeueMin(); // here is the problem
colorCell(world, currNode, GREEN);
greenNodes.add(currNode);
if (currNode == end) {
break;
}
Vector<Loc> neighbourNodes = getNeighbourNodes(currNode, world);
foreach (Loc node in neighbourNodes) {
if (greenNodes.contains(node)) {
continue;
}
if (!yellowNodes.contains(node)) {
colorCell(world, node, YELLOW);
yellowNodes.add(node);
double distance = distanceMap.get(currNode) + costFn(currNode, node, world);
distanceMap.put(node, distance);
node.parent = &currNode; // here is the problem
queue.enqueue(node, distance);
} else {
double distance = distanceMap.get(node);
double currDistance = distanceMap.get(currNode) + costFn(currNode, node, world);
if (distance > currDistance) {
distanceMap.put(node, currDistance);
node.parent = &currNode;
queue.decreaseKey(node, distance);
}
}
}
}
return vec;
}
Here Grid is just a 2D array and costFn just calculates the cost from one location to the next. The way I try to save the path is assign the location of the previous node to current one. Here's the problem: when I traverse the neighbouring nodes of currNode and set the parent of each one as the &currNode, after setting currNode to the new element from the queue, it now refers to other node, so the node's parent now refers to itself, infinitely.
I've tried many different ways of overcoming this problem, creating new nodes in heap and other stuff, but they didn't really work. I've also tried to create other struct and use that to save locations, but I feel like there should be a fairly simple way to resolve this issue.
I hope my explanation isn't too confusing, I've added markers as comments to which lines cause the problem. Also, I say "node", but the struct is called Loc:
struct Loc {
int row;
int col;
Loc* parent;
};

Finding the number of edges and performing a topo sort in my graph implementation

I have been working on a graph implementation for the last few days. All of this is really new to me, and I am stuck on two parts of my implementation. I am implementing a digraph of courses from an input file. From the file, I can determine which courses are prereqs for other courses. I then create a digraph with courses as nodes, and edges connecting courses that are prereqs. I also want to find the total number of nodes and edges, and perform a topological sort on the graph (I will later be adding weights to the edges). Here is my implementation.
Digraph.h
class vertex{
public:
typedef std::pair<int, vertex*> ve;
std::vector<ve> adjacency;
std::string course;
vertex(std::string c){
course = c;
}
};
class Digraph{
public:
void addVertex(std::string&);
void addEdge(std::string& from, std::string& to, int cost);
typedef std::map<std::string, vertex *> vmap;
vmap work;
int getNumVertices();
int getNumEdges();
void getTopoSort();
};
Digraph.cpp
void Digraph::addVertex(std::string& course){
vmap::iterator iter = work.begin();
iter = work.find(course);
if(iter == work.end()){
vertex *v;
v = new vertex(course);
work[course] = v;
return;
}
}
void Digraph::addEdge(std::string& from, std::string& to, int cost){
vertex *f = (work.find(from)->second);
vertex *t = (work.find(to)->second);
std::pair<int, vertex *> edge = std::make_pair(cost, t);
f->adjacency.push_back(edge);
}
Finding the number of nodes was easy just return work.size. I have confirmed this is working properly. I am lost on how I would return the number of edges in my graph. It seems it would be simple, but everything I tried doesn't work. Secondly, I am completely lost on how to perform a topological sort on this graph. Any assistance is appreciated.
A simple way would be to iterate through all vertices in your graph, add up their neighbor counts and then divide by two:
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count / 2;
}
To use the range based for loop, you need to use c++11. With g++ that would be --std=c++11 on the command line.
EDIT:
I just realized you have a directed graph, and you probably want to count one for each direction. In such case: don't divide by two!
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count;
}
First, for the number of edges, it would be simpler to count them directly when you build the graph (just add a counter in your Digraph class and increment it each time you add an edge … )
For the topological sort, first I have a question: your edges are from prereqs to dependant courses ? That is you have a link A -> B if A is a prereq of B ? If this not the case, you need to invert your graph.
You to main algorithm in order to build a topological sort: one based on a simple DFS (http://en.wikipedia.org/wiki/Depth-first_search) and the other relying on in-degrees (http://en.wikipedia.org/wiki/Directed_graph#Indegree_and_outdegree) of your vertices (courses in your case.)
Normally, you need to verify that your graph doesn't contain any cycle, which will normally be the case if your data are coherent.
Let's consider the DFS based algorithm: a DFS traverses each vertices from a given root following edges as they appear. We can easily prove that order of last encounter of a vertex forms a reverse topological order. So, all we need is to push in a stack the current vertex after the calls on its successors.
I made a quick and dirty implementation for you, using C++11 again.
First, add the following to the Digraph class:
typedef std::unordered_set<vertex*> marks_set;
marks_set marks;
typedef std::deque<vertex*> stack;
stack topo;
void dfs(vertex* vcur);
Then here comes the code:
void Digraph::dfs(vertex* vcur) {
marks.insert(vcur);
for (const auto & adj : vcur->adjacency) {
vertex* suc = adj.second;
if (marks.find(suc) == marks.end()) {
this->dfs(suc);
} // you can detect cycle in the else statement
}
topo.push_back(vcur);
}
void Digraph::getTopoSort() {
// It should be a good idea to separate this algorithm from the graph itself
// You probably don't want the inner state of it in your graph,
// but that's your part.
// Be sure marks and topo are empty
marks.clear();
topo.clear();
// Run the DFS on all connected components
for (const auto & v : work) {
if (marks.find(v.second) == marks.end()) {
this->dfs(v.second);
}
}
// Display it
for (const auto v : topo) {
std::cout << v->course << "\n";
}
}
The code compiles but I haven't tested. If for any reasons you have an issue with the recursive algorithm (the function Digraph::dfs), it can be derecursified using a stack containing the parent of the target vertex and the iterator to the current successor, the iterator reach the end of the adjacency list, you can push the parent in the topological sort.
The other algorithm is almost as simple: for each vertices you need to count the number of predecessor (in-degree) which can be done while building the graph. In order to compute the topological sort, you look for the first vertex with a in-degree of 0 (no predecessor), you then decrease the in-degree of all its successors and continue with the next vertex with 0. If the graph has no cycle, there will always be a vertex with a in-degree of 0 (at beginning of course, but also during the algorithm run as you decrease it) until all vertices have been seen. The order of vertices encounter form a topological sort (this is related to the Bellman shortest-path algorithm.)
Note that these 2 algorithms are listed here: http://en.wikipedia.org/wiki/Topological_sorting. The one using in-degree is described in terms of removing edges which we simply simulate by decreasing the in-degree (a far less destructive approach … )

How to transform C program into classes

so I've been working on this program and its objective was to use recursion and an adjacency matrix to find how many possible routes a person could take to get through a subway system without going over a track more than once. That was self explanatory for me but now I'm lost on program 2 which is to do the same problem from program 1 in C++ and using three classes and recursion. The classes are suppose to be SubwaySystem, Station, and Track. I don't really know how to go about the transition from a simple adjacency matrix into three classes? It seems counterproductive since it seems more complicated. I have been working on it for a while know and I can't seem to utilize all three classes.
What I have tried: My approach was I created 1 Subway System with 12 Stations, and each station with an array of Tracks. For example, Station A has one station it can go to which is B. In Station A there is an array of 12 tracks but only 1 track is activated. However I keep running to errors since I tried to initialize the arrays in the Track class and then use them in the SubwaySystem class. Then trying to use recursion to get all possible routes makes it that much more difficult. I really don't know how to figure this out.
The adjacency matrix in the my code pretty much maps out the entire connection from station to station. The station are A - L corresponding to each row/column. I don't know how to represent this in c++ without using an adjacency matrix.
My code in C (program 1):
#include <stdio.h>
void routesFinder(int row, int col);
char station[13] = "ABCDEFGHIJKL";
char order[25] = "A";
int subway[12][12] = {{0,1,0,0,0,0,0,0,0,0,0,0},
{1,0,1,1,1,1,0,0,0,0,0,0},
{0,1,0,0,1,0,0,0,0,0,0,0},
{0,1,0,0,1,0,0,0,0,0,0,0},
{0,1,1,1,0,0,1,1,0,0,0,0},
{0,1,0,0,0,0,0,1,0,0,0,0},
{0,0,0,0,1,0,0,0,0,0,1,0},
{0,0,0,0,1,1,0,0,1,1,1,0},
{0,0,0,0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,1,1,1,1,0,1},
{0,0,0,0,0,0,0,0,0,0,1,0}};
int paths = 0, i = 1;
int main(){
routesFinder(0, 0); //start with first station row, first column
printf("\n%d days before repeating a route.\n", paths);
return 0;
}
void routesFinder(int row, int col) {
while (col < 12) { //go through columns of a row
if (subway[row][col] == 0) { // if no station is found in row
if (row == 11) { // station found
paths++;
printf("Route %d: %s.\n", paths, order);
return;
}
col++;
if (row != 11 && col == 12) { //backtracking from deadend
return;
}
}
if (subway[row][col] == 1) {
order[i] = station[col]; //add station to route
i++; //increment, prepare for next route
subway[row][col] = 0; //no track forward
subway[col][row] = 0; // or backward
routesFinder(col, 0); //recursion, look for path in new row
order[i] = '\0'; //remove route
i--; //decrement, prepare for next route
subway[row][col] = 1; //restore path
subway[col][row] = 1; // restore path
col++; //returning from deadend, check for next open path
if (row != 11 && col == 12) { //return from deadend
return;
}
}
}
}
In general I can tell you that in c++ in particular and in object oriented in general,
each object should have its unique role in the system. Each is encapsulating a behavior and a knowledge that are its own and sole responsibility.
As for you specific problem - Without getting too deeply into the problem, I think the idea would be:
#include <iostream>
#include <string>
#include <vector>
class Track;
typedef std::vector<Track*> TrackList;
class Station
{
public:
Station( std::string name ) : _name( name ){};
~Station(){}
public:
const std::string& GetName() const
{ return _name; }
TrackList& GetTrackList()
{ return _trackList; }
void AddTrack( Track& track )
{ _trackList.push_back( &track ); }
private:
std::string _name;
TrackList _trackList;
};
class Track
{
public:
Track( Station& edgeA, Station& edgeB )
:
_edgeA( edgeA ),
_edgeB( edgeB ),
_wasVisited( false )
{
edgeA.AddTrack( *this );
edgeB.AddTrack( *this );
}
~Track(){}
public:
bool WasVisited() const
{ return _wasVisited; }
void SetVisited()
{ _wasVisited = true; }
public:
Station& GetEdgeA()
{ return _edgeA; }
Station& GetEdgeB()
{ return _edgeB; }
private:
Station& _edgeA;
Station& _edgeB;
bool _wasVisited;
};
class SubwaySystem
{
public:
SubwaySystem() {}
~SubwaySystem() {}
public:
void Traverse( Station& start )
{
TrackList& tracks = start.GetTrackList();
TrackList::iterator it = tracks.begin();
while ( it != tracks.end() )
{
if ( ! (*it)->WasVisited() )
{
std::cout << (*it)->GetEdgeA().GetName() << "-->" << (*it)->GetEdgeB().GetName() << ",";
(*it)->SetVisited();
Traverse( (*it)->GetEdgeB() );
}
++ it;
}
std::cout << std::endl;
}
};
int main()
{
Station A( "A" );
Station B( "B" );
Station C( "C" );
Station D( "D" );
Station E( "E" );
Track AB( A, B );
Track BC( B, C );
Track CA( C, A );
Track CD( C, D );
Track CE( C, E );
Track AE( A, E );
SubwaySystem subway;
subway.Traverse( A );
}
The output to this is
A-->B,B-->C,C-->A,A-->E,C-->E,
C-->D,
Surly you can 'play' with the Traverse function and put the printings in other places,
select another end-recursion condition, etc.
Notice how clean main() is.
You just declare the Stations and the Tracks and the voodoo happens.
Adding more tracks is simple, just describe the link and that's all, the track wad 'added' to the subway.
Other parts of the applications are also very clean, as each class knows exactly what it should and nothing more.
One possible way would to have the subway system hold control over all the stations. The stations would then have tracks that knew the origin (which station they came from) and the destination (which station they could go to).
The adjacency matrix would be broken up, the whole thing is represented inside the subway system, each row/column is represented in the stations, and each 1/0 is represented by the tracks. There would be no track for a zero.
Which paths to take would be decided at the station level, with which tracks being used/destinations already have been gone to. The tracks could have a property that keep track if they have been ridden on.
If you were doing this in C, you might have structures like this
typedef struct node node;
typedef struct edge edge;
typedef struct graph graph;
struct graph { // subway system
node *nodes; // stations
};
struct node { // station
char *name;
edge *edges; // tracks connected to this station
node *next; // next node in graph
bool visited;
}
struct edge { // track
node *src; // from station
node *dst; // to station
edge *next; // next track, this station
bool visited;
}
Transforming that into classes should be easy. Except that they might want you to use stl data structures instead of simply inlining the lists like I did.
The simple recursive graph algorithms map nicely to these data structures.
The idea of recursion for counting is a little hard to get, but let me try to explain at least that part.
So you know how strlen works, in C, right? You walk the array and keep a count. But here's a recursive version
unsigned int strlen(const char * string) {
if (*string == '\0') { return 0; }
else return 1 + strlen(string + 1);
}
Do you see how that works? Not that useful when walking an array where you can use a simple counter, but when you are dealing with issues where there are multiple possible combinations of doing things, or multiple ways of going, it works nicely. For example, if you wanted to count the number of nodes in a binary tree, you might do something like.
unsigned int treecount(NODE * node) {
if (node == NULL) { return 0;}
else return 1 + treecount(node->left) + treecount(node->right);
}
Hopefully that helps. Charlie Burns is probably right that doing it with a graph is a good idea.

how to use Dijkstra c++ code using array based version

I need to use (not implement) an array based version of Dijkstras algo .The task is that given a set of line segments(obstacles) and start/end points I have to find and draw the shortest path from start/end point.I have done the calculating part etc..but dont know how to use dijkstras with my code.My code is as follows
class Point
{
public:
int x;
int y;
Point()
{
}
void CopyPoint(Point p)
{
this->x=p.x;
this->y=p.y;
}
};
class NeighbourInfo
{
public:
Point x;
Point y;
double distance;
NeighbourInfo()
{
distance=0.0;
}
};
class LineSegment
{
public:
Point Point1;
Point Point2;
NeighbourInfo neighbours[100];
LineSegment()
{
}
void main()//in this I use my classes and some code to fill out the datastructure
{
int NoOfSegments=i;
for(int j=0;j<NoOfSegments;j++)
{
for(int k=0;k<NoOfSegments;k++)
{
if( SimpleIntersect(segments[j],segments[k]) )
{
segments[j].neighbours[k].distance=INFINITY;
segments[j].neighbours[k].x.CopyPoint(segments[k].Point1);
segments[j].neighbours[k].y.CopyPoint(segments[k].Point2);
cout<<"Intersect"<<endl;
cout<<segments[j].neighbours[k].distance<<endl;
}
else
{
segments[j].neighbours[k].distance=
EuclidianDistance(segments[j].Point1.x,segments[j].Point1.y,segments[k].Point2.x,segments[k ].Point2.y);
segments[j].neighbours[k].x.CopyPoint(segments[k].Point1);
segments[j].neighbours[k].y.CopyPoint(segments[k].Point2);
}
}
}
}
Now I have the distances from each segmnets to all other segments, amd using this data(in neighbourinfo) I want to use array based Dijkstras(restriction ) to trace out the shortest path from start/end points.There is more code , but have shortened the problem for the ease of the reader
Please Help!!Thanks and plz no .net lib/code as I am using core C++ only..Thanks in advance
But I need the array based version(strictly..) I am not suppose to use any other implemntation.
Dijkstras
This is how Dijkstra's works:
Its not a simple algorithm. So you will have to map this algorithm to your own code.
But good luck.
List<Nodes> found; // All processed nodes;
List<Nodes> front; // All nodes that have been reached (but not processed)
// This list is sorted by the cost of getting to this node.
List<Nodes> remaining; // All nodes that have not been explored.
remaining.remove(startNode);
front.add(startNode);
startNode.setCost(0); // Cost nothing to get to start.
while(!front.empty())
{
Node current = front.getFirstNode();
front.remove(current);
found.add(current);
if (current == endNode)
{ return current.cost(); // we found the end
}
List<Edge> edges = current.getEdges();
for(loop = edges.begin(); loop != edges.end(); ++loop)
{
Node dst = edge.getDst();
if (found.find(dst) != found.end())
{ continue; // If we have already processed this node ignore it.
}
// The cost to get here. Is the cost to get to the last node.
// Plus the cost to traverse the edge.
int cost = current.cost() + loop.cost();
Node f = front.find(dst);
if (f != front.end())
{
f.setCost(std::min(f.cost(), cost));
continue; // If the node is on the front line just update the cost
// Then continue with the next node.
}
// Its a new node.
// remove it from the remaining and add it to the front (setting the cost).
remaining.remove(dst);
front.add(dst);
dst.setCost(cost);
}
}