dijkstra algorithm incorrect conditional - c++

I am working on a dijkstra algorithm using priority queues. I have been doing a lot of research, and I thought my code was following the algorithm, but I cannot get into the conditional when comparing for the shortest paths
void dijkstra( int startingID ) {
priority_queue<Vertex*, vector<Vertex*>, PathWeightComparer> dijkstra_queue{};
vector<Vertex*> vert;
vert = _vertices;
int n = vert.size();
vector< double > dis(n);
for (int i = 0; i < n; i++)
{
dis[i] = std::numeric_limits< double >::infinity();
}
vert[startingID]->setPathWeight(startingID);
dis[startingID] = 0;
Vertex* temp = vert[startingID];
dijkstra_queue.push(temp);
while (!dijkstra_queue.empty())
{
double dist = dijkstra_queue.top()->getPathWeight();
double u = dijkstra_queue.top()->getId();
dijkstra_queue.pop();
for (auto i : vert)
{
double v = i->getId();
double weight = i->getPathWeight();
double distance_total = dist + weight;
cout << "distance_total " << distance_total << " dis[v] " << dis[v] << endl;
if (distance_total < dis[v]) //PROBLEM
{
dis[v] = distance_total;
Vertex* temp2 = i;
temp2->setPathWeight(dis[v]);
dijkstra_queue.push(temp2);
}
}
}
}
};
Here is the graph class
class Graph
{
vector<Vertex*> _vertices; // All vertices in the graph (vertex id == index)
int _last_startingID = -1;
And here is the vertex class
class Vertex
{
private:
int _id; // ID (key) of given vertice
bool _known = false; // Dijkstra's algorithm "known" flag
Vertex* _path = nullptr; // Dijkstra's algorithm parent vertex pointer
// Weight of path through graph - starts at a true infinity (inf)
double _path_weight = std::numeric_limits<double>::infinity();
I tried to only include the code that was relavent to only the dijkstra function, but if anything is unclear I can add more.

Your implementation of the algorithm is incorrect.
After you pop() vertex u from the queue (because it's distance from the source is the lowest) you should ONLY inspect vertices that are directly reachable from u (i.e. an edge exists from u to that vertex).
Your current implementation seems to be looping through ALL vertices regardless of whether they are directly reachable from u or not, and perhaps as a result, you are doing something strange with the distance calculation that makes no sense. More specifically, distance_total in your implementation seems nonsensical.
The key idea behind Dijkstra's algorithm is:
dis[u] = must be shortest path from source to u since u was popped.
dis[v] = current_known_distance_to_v
Then, for all v where edge exists from u to v:
IF dis[u] + weight(u, v) < dis[v]:
// going via u is better than the current best known distance to v
dis[v] = dis[u] + weight(u, v)

Related

Shortest path with file as input

I'm creating a graph taking a file as input and I want to calculate the shortest path, to do so I used SPF algorithm. I have a few file I can use to see if it works, and here comes the problem because it works until I try it with the biggest one (which has over 1 million vertex and 2 million edges), considering that the second for dimension has about 700k vertex and 100 million edges and with it it works just fine, what do you think the problem is? I just need some hint I really can't figure it out!
Please be patient with me, I'm new in this comunity and to coding in general, I'm just trying to learn and understand things properly...
It's returning error 3221225725
// Function to compute the SPF algorithm
void shortestPathFaster(int S, int V)
{
// Create array d to store shortest distance
int d[V + 1];
// Boolean array to check if vertex
// is present in queue or not
bool inQueue[V + 1] = { false };
// Initialize the distance from source to
// other vertex as INT_MAX(infinite)
for (int i = 0; i <= V; i++) {
d[i] = INT_MAX;
}
d[S] = 0;
queue<int> q;
q.push(S);
inQueue[S] = true;
while (!q.empty()) {
// Take the front vertex from Queue
int u = q.front();
q.pop();
inQueue[u] = false;
// Relaxing all the adjacent edges of
// vertex taken from the Queue
for (int i = 0; i < graph[u].size(); i++) {
int v = graph[u][i].first;
int weight = graph[u][i].second;
if (d[v] > d[u] + weight) {
d[v] = d[u] + weight;
// Check if vertex v is in Queue or not
// if not then push it into the Queue
if (!inQueue[v]) {
q.push(v);
inQueue[v] = true;
}
}
}
}
// Print the result
print_distance(d, V);
}
The problem is most likely here:
int d[V + 1];
Firstly, variable length arrays are non-standard. Secondly, if V is large you will overflow the stack.
Solution: replace this with std::vector. bool inQueue[V + 1] should be treated similarly.
Also, replace char buffer[BUFFER_SIZE]; with std::string. You'll be glad you did.

find if a structure already exists in a vector c++

I have to find the weight between all edges in a graph, so since the edges are bidirectional I dont want to include 2 -> 1 if I already have 1 -> 2 (since they will have the same weight). The edges are stored in a vector from structure Edge. My initial idea was to look up, if an edge that has the start and end positions swapped and has the same weight already exists, and if this is the case, just dont do anything. However, I dont exactly know how to put it into code, so any help would be appreciated. Also any approaches that could optimise the solution are also welcome.
struct Vertex {
Vertex(const int i = 0) : index {i}, key {max_key}, parent_index {undef}, processed {false} {}
int index; // vertex identifier
int key; // temporary minimal weight (Prim algorithm)
int parent_index; // temporary minimal distance neighboor vertex (Prim algorithm)
int processed; // flag used to mark vertices that are already included in V'
static constexpr int max_key = std::numeric_limits<int>::max();
static const int undef = -1;
};
struct Edge {
Edge(int va, int vb, int w) : vi1 {va}, vi2 {vb}, weight {w} { }
int vi1; //start point
int vi2; //end point
int weight;
};
struct Graph {
int N; // number of vertices
std::vector<Vertex> V; // set of vertices
std::vector<Edge> E; // set of edges
std::vector<Edge> MST; // minimal spanning tree
const int* weights_table; // weights given as distance matrix
};
The problem is here in find I know this is a lot of irrelevant code, but I post it so that you can picture it more clearly. If there is no connection between 2 vertices they have weight of -1
// construct vertices and edges for a given graph
void createGraph(Graph& G) {
// TODO 5.1a: clear V and E and insert all vertex objects and edge objects
// - vertices are numbered (labeled) from 0 to N-1
// - edges exist if and only if there is positive distance between two vertices
// - edges are bidirectional, that is, edges are inserted only once between two vertices
G.E.clear();
G.V.clear();
for(int i = 0; i < G.N; i++){
Vertex V (i);
G.V.push_back(V);
}
for(int i = 0; i < G.N; i++){
for(int j = 0; j < G.N; j++){
Edge Ed (i,j,0);
int weight = getWeight(G,i,j);
if(weight > 0){
Ed.weight = weight;
auto it = find(G.E.begin(), G.E.end(), ....);
if( it != G.E.end() ) continue;
G.E.push_back(Ed);
}
}
}
}
Thanks!
since the edges are bidirectional
You can construct Edges such that v1 <= v2, then there is only one representation of each possible edge.
struct Edge {
Edge(int va, int vb, int w) : vi1 {std::min(va, vb)}, vi2 {std::max(va, vb)}, weight {w} { }
int vi1; // earlier point
int vi2; // later point
int weight;
};
Aside: prefer constructing the Edge in place
for(int i = 0; i < G.N; i++){
for(int j = G.N - 1; j >= 0 + i; j--){
int weight = getWeight(G,i,j);
if(weight > 0){
G.E.emplace_back(i, j, weight);
}
}
}
Okay, I think I got it, by changing the second for loop to look this way, but I am also curious to see how would the syntax would look like if find is being used
for(int i = 0; i < G.N; i++){
for(int j = G.N - 1; j >= 0 + i; j--){
Edge Ed (i, j , 0);
int weight = getWeight(G,i,j);
if(weight > 0){
Ed.weight = weight;
G.E.push_back(Ed);
}
}
}

Finding a path in a graph with random edges

We have n vertices (where n is less than 100 000) and m random edges (where m is less than 10 000 000). We want to find a path between 2 given vertices. If there is no path we will just print -1.
My algorithm is to build a tree. Every vertex has a disjoint_index (i) which shows that all vertices with disjoint_index (i), are connected.
The default value of disjoint_index is the index of each vertex. After finding an edge between vertex v and u, I check if they are connected. If they are connected, I do nothing. Else I change the disjoint_index of u and all the vertices connected to u by a function named (dfs).
Here is the code of the function to build this tree in c++:
struct vertex{
int disjoint_index;
vector<int> adjacent;
};
void build_tree(int m, int s, int e)
{
for(int i = 0; i < m; i++)
{
int u = kiss() % n;
int v = kiss() % n;
if(disjoint_counter[u] > disjoint_counter[v])
{
int temp = u;
u = v;
v = temp;
}//counter v > u
if(ver[v].disjoint_index != ver[u].disjoint_index)
{
ver[v].adjacent.push_back(u);
ver[u].adjacent.push_back(v);
dfs(v, u, ver[v].disjoint_index);
disjoint_counter[v] += disjoint_counter[u];
}
if(ver[s].disjoint_index == ver[e].disjoint_index)
return;
}
}
void dfs(int parent, int v, int d)
{
ver[v].disjoint_index = d;
for(int i = 0; i < ver[v].adjacent.size(); i++)
{
if(ver[v].adjacent[i] == parent)
continue;
dfs(v, ver[v].adjacent[i], d);
}
}
Here you can skip kiss, It's just a function that returns two vertices and shows that there is an edge between u and v.
disjoint_counter[i] shows how many vertices are in connected group i.
After building this tree I will find a path with a simple dfs. The time limit is 1s and I get Time Limit Exceeded on some test cases.
Edit: Memory is limited so I can't save all the edges.
Maximum memory I can use is 32MB.
I used the disjoint set union algorithm, it developed speed.

How to represent a graph in c++

I would like to write prims and dijkstra algoritms that create a MST. But I do not know what is the best way to represent graph in c++.
I could represent an edge by pair of two ints for example vector 0 to 1 would be pair(0,1);
typedef pair<int, int> Edge;
And then the prims function would take Vector of pairs that consist of an edge and its weight.
void prims(vector<pair<Edge, int>>);
I think that this way is not the best one, could anyone tell me what way would be the best to represent a graph?
I have been implementing Dijkstra some time ago for finding paths in binary images. I represented a graph as a vector of a struct GraphNodes that contained a vector of Connections that contained all the connections of the node to other nodes. Each connection has its distance attribute, which is the weight of the edge. Here are the two structs I used:
//forward declaration
struct GraphNode;
struct Connection {
Connection() : distance(1) { };
Connection(GraphNode* ptr, double distance) : ptr(ptr), distance(distance) { };
bool operator==(const Connection &other) const;
GraphNode* ptr;
double distance;
};
struct GraphNode {
GraphNode() : connections(8), predecessor(NULL), distance(-1) { };
cv::Point point;
double distance;
GraphNode* predecessor;
std::vector<Connection> connections;
};
bool Connection::operator==(const Connection &other) const {
return ptr == other.ptr && distance == other.distance;
}
The distance attribute of the GraphNode is the distance it currently has in the Dijkstra algorithm, so the distance of the shortest currently known distance to the start node. At the beginning this is initialized with -1.
I then implemented the Dijkstra algorithm like this:
std::vector<cv::Point> findShortestPathDijkstra(std::vector<GraphNode>& graph, int startNodeIndex, int destNodeIndex) const {
GraphDistanceSorter sorter(graph);
std::set<GraphNode*, GraphDistanceSorter> unusedNodes(sorter);
for (int i = 0; i < graph.size(); ++i) {
unusedNodes.insert(&graph[i]);
}
while (unusedNodes.size() > 0) {
GraphNode* currentNode = *unusedNodes.begin();
if (currentNode->distance == -1) {
return std::vector<cv::Point>();
}
if (currentNode == &graph[destNodeIndex]) break;
unusedNodes.erase(currentNode);
//update distances of connected nodes
for (Connection const& con : currentNode->connections) {
/*here we could check if the element is really in unusedNodes (search, O(log n)), but this would
actually take longer than calculating the new distance (O(1)), which will in this case always be greater
than the old one, so the distance is never updated for nodes not in unusedNodes ()*/
double newDistance = currentNode->distance + con.distance;
if (newDistance < con.ptr->distance || con.ptr->distance == -1) {
unusedNodes.erase(con.ptr);
con.ptr->distance = newDistance;
con.ptr->predecessor = currentNode;
unusedNodes.insert(con.ptr);
}
}
}
//now trace back the path as a list of points
std::vector<cv::Point> points;
GraphNode* current = &graph[destNodeIndex];
points.push_back(current->point);
while (current != &graph[startNodeIndex]) {
if (current->predecessor == NULL) return std::vector<cv::Point>();
current = current->predecessor;
points.push_back(current->point);
}
return points;
}
As you see there is a set unusedNodes that contains all the unused nodes so far. It only contains pointers on graphNodes. The actual graph representation is in the vector. The advantage of having a set is, that it is always sorted according to a certain criterion. I implemented my own sorter GraphDistanceSorter that sorts the GraphNodes according to the distance criterion of the Dijkstra algorithm. This way I just have to pick the first node from the set and know that it's the one with the smallest distance:
struct GraphDistanceSorter {
bool operator() (const GraphNode* lhs, const GraphNode* rhs) const;
};
bool GraphDistanceSorter::operator() (const GraphNode* lhs, const GraphNode* rhs) const {
if (lhs->distance == rhs->distance) {
return lhs < rhs;
} else {
if (lhs->distance != -1 && rhs->distance != -1) {
if (lhs->distance != rhs->distance) {
return lhs->distance < rhs->distance;
}
} else if (lhs->distance != -1 && rhs->distance == -1) {
return true;
}
return false;
}
}
The two main ways to represent graphs learned in theoretical computer-science are adjacency matrix and adjacency lists.
Adjacency Matrix is as shown in the photo below is an n*n matrix and a[i][j] represents the edge between node i and node j so if it's a weighted graph it can be an integer instead of a boolean value for unweighted graphs.
adjacency matrix (photo source: google)
On the other hand, adjacency lists is a set of linked-lists (n-set to be exact), the i-th set has exactly the nodes i is connected to.
in this case you will need some additional way to save edge distance for example you can build your own class Edge as following
class Edge
{
int destination, length;
Edge* next = 0;
}
and use it for your linked-list. How ever I am used to std::vector<std::pair<int, int>> a[N] to define a list of pairs and a[i][j].first would be the j-th neighbor of nod i and a[i][j].second the length of the edge between them.
For undirected graph your can add i to j neighbors as well.
So it's also a flexible way to represent graphs.
adjacency lists (image source: google photos)
So now let's talk complexity, I will try to keep it as simple as possible:
We habe n lists, each has the #(edges going out of node i)
so the total number is sum of this numbers which is the total number of edges E.
That means place complexity is O(E) which is at most 5 * n in a sparse-graph in comparison to O(N^2) in adjacency matrix. (We need a linear factor of E to represent it).
Now let's consider visiting all neighbors of a nod x:
in adjacency matrix we will go through the whole x-th line and if it's not 0 there's an edge there which is O(N).
In adjacency lists it's again exactly the number of neighbors of x which can though reach O(N).
But if we are visiting all neighbors of all Nodes (which is the case in Dijkstra when updating dis array), you will need to visit n elements n times in adjacency lists which is also O(N^2) time complexity while in adjacency lists it's exactly the sum of the number of neighbors - again E. which means we need also O(E) to visit all neighbors of all edges.
And sind all edges are given usually in the input O(E) would pass as calculation time, but O(N^2) would be a high complexity for constraints of N <= 10^6 for example.
At the end I will leave you with my usual implementation of diffreent variants of graphs using adjacency lists (vector as a list):
#include<iostream>
#include<vector>
int main(){
const int N = 5;
int n, e;
std::vector<std::pair<int, int>> graph[N], inverse[N];
std::vector<int> unweighted[N], undirectedUnweighted[N];
std::cin >> n >> e;
for(int i = 0; i < e; i++)
{
int x, y, z;//z is length of edge
std::cin >> x >> y >> z;
//substitute 1 from x, y if they starts from 1
graph[x].push_back(std::make_pair(y, z));
inverse[y].push_back(std::make_pair(x, z));
unweighted[x].push_back(y);
undirectedUnweighted[x].push_back(y);
undirectedUnweighted[y].push_back(x);
}
return 0;
}
Simple form for representing graph (finding neighbors and degrees for vertices)
#include<iostream>
/** Representing graphs in c++ programming language */
using namespace std;
int main() {
cout << "\033[1;33mNote: if there are no neighbourhood between vertices write '-' symbol!\033[0m\n"<<endl;
int number_of_vertices;
cout<<"\033[1;32mPlease enter number of vertices: \033[0m";
cin>>number_of_vertices;
int max_num_of_neighbours;
cout<<"\033[1;32mPlease enter maximum number of neighbours: \033[0m";
cin>>max_num_of_neighbours;
char array[number_of_vertices][max_num_of_neighbours];
char vertices[number_of_vertices];
cout<<"\033[1;33mPlease sign vertices with lowercase alphabet letters: \033[0m"<<endl;
for(int i = 0; i < number_of_vertices; i ++) {
cout<<(i+1)<<" = ";
cin>>vertices[i];
}
for(int i = 0; i < number_of_vertices; cout<<endl, i ++) {
cout<<"\033[1;32mPlease enter neighbours for \033[0m"<<vertices[i]<<" --> ";
for(int j = 0; j < max_num_of_neighbours; j ++) {
cin>>array[i][j];
}
}
for(int i = 0; i < number_of_vertices; cout<<endl, i ++) {
cout<<"\033[1;34mNeighbours for \033[0m"<<"\033[1;35m"<<vertices[i]<<"\033[0m"<<" --> ";
int deg = 0;
for(int j = 0; j < max_num_of_neighbours; j ++) {
if(array[i][j] != '-') {
deg ++;
}
if(array[i][j] == '-') {
cout<<"\033[1;31m"<<array[i][j]<<"\033[0m"<<"\t";
} else {
cout<<"\033[1;32m"<<array[i][j]<<"\033[0m"<<"\t";
}
}
cout<<"\033[1;36m"<<"deg["<<"\033[0m"<<"\033[1;35m"<<vertices[i]<<"\033[0m"<<"\033[1;36m"<<"] = "<<"\033[0m"<<deg;
}
cout<<endl<<"\033[1;33mRemember that '\033[1;31m-\033[0m\033[1;33m' shows when two vertices aren't adjacent!\033[0m"<<endl;
}
For adding interactivity I used How do I output coloured text to a Linux terminal? for changing color of text

Traverse a graph from a starting point and ending at the starting point C++

I'm working on a C++ program where we must traverse a graph of vertices and weighted edges in a way that we start at a user-specified vertex and then end at the same vertex after a certain desired distance has been traveled.
I am not sure how to implement this with code, but I have this so far:
void DijkstrasShortestPath()
{
while (vertices.size() != 0)
{
Vertex* u = extract_min(vertices);
vector<Vertex*>* adjVertex = AdjVertices(u);
const int size = adjVertex->size();
for (int i=0; i<size; ++i)
{
Vertex* v = adjVertex->at(i);
int distance = travel_dist(u, v) +
u->distFromStart;
if (distance < v->distFromStart)
{
v->distFromStart = distance;
v->previous = u;
}
}
delete adjVertex;
}
}
Vertex* extract_min(vector<Vertex*>& vertices)
{
int size = vertices.size();
if (size == 0) {
return NULL;
}
int minimum = 0;
Vertex* min = vertices.at(0);
int i = 0;
for( i=1; i<size; ++i)
{
Vertex* temp = vertices.at(i);
if( temp->distFromStart < min->distFromStart) {
min = temp;
minimum = i;
}
}
vertices.erase(vertices.begin() + minimum);
return min;
}
vector <Vertex*>* AdjVertices(Vertex* vert)
{
vector<Vertex*>* adjVertex = new vector <Vertex*> ();
const int size = edges.size();
for(int i=0; i<size; ++i)
{
Edge* edge = edges.at(i);
Vertex* adjacent = NULL;
if (edge->intersection1 == vert)
{
adjacent = edge->intersection2;
}
else if (edge->intersection2 == vert)
{
adjacent = edge->intersection1;
}
if (adjacent && vertices_check(vertices, adjacent))
{
adjVertex->push_back(adjacent);
}
}
return adjVertex;
}
int travel_dist(Vertex* u, Vertex* v)
{
const int size = edges.size();
for(int i=0; i<size; ++i)
{
Edge* edge = edges.at(i);
if (edge->street_connection(u, v))
{
return edge->distance;
}
}
return -1;
}
bool vertices_check(vector<Vertex*>& vertices, Vertex* vert)
{
const int size = vertices.size();
for(int i=0; i<size; ++i)
{
if (vert == vertices.at(i))
{
return true;
}
}
return false;
}
This is essentially the Dijkstra's Shortest Path algorithm, which is not exactly what I want. What I'm trying to do is get the program to calculate a route thats distance is within 1 unit of a user-specified distance and starts and ends at the same vertex.
Is there any way I can do that by changing what I have?
Does this call for a Breadth-First Search or a Depth-First search instead of Dijkstra's Algorithm?
Dijkstra's algorithm will only store the shortest path from the start node to any other node. What you want instead is to keep track of all paths that lead to a node. If you have those, you can check every time you find a new path to a node if there is a path that has been found before whose length plus the length of the new path is within one unit of the user specified distance. If you then walk one path forward and the other one back you have your loop.
One possible method.
You could use a bounded best-first search.
Create a structure P which stores a list of nodes forming the potential loop, along with the length of the loop created so far.
Seed the search at the specified vertex S by making a separate P-structure for each of the nodes which S links to. Add these P-structures to a priority queue which is sorted by the length of the path described by the P-structure.
Consider each of these nodes in turn removing their P-structures from the priority queue, copying their P-structures, and appending the nodes they link to. If the node to be added is already present in the P-structure and not it is not S, then discard the structure and do not consider that route any longer. Similarly, if any path exceeds the specified cost C, then discard that path and do not consider it any longer. If the path has not been discarded, add its associated P-structure to the priority-queue.
If S does appear in a P-structure twice and the length of the path described by the P-structure is within the permitted range, then exit successfully. If not, continue the search until the priortiy-queue is empty.
You may be able speed up the algorithm by using an admissible heuristic to guesstimate the distance from a given node to S, adding this to the established cost of the path-in-progress, and using the sum as the sorting key for the priority queue. Such heuristics are at the heart of the A* algorithm, which may be of interest to you.
Is this clear? If not, I could writing a short example code.