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.
Related
I have tried to solve the problem Rerouting at hacker rank. I am posting here for help as competition is over.
https://www.hackerrank.com/contests/hack-the-interview-v-asia-pacific/challenges/rerouting
I have tried to solve problem using Strong connected components, but test cases failed. I can understand we have to remove cycles. But I stuck how to approach problem. Below is solution i have written. I am looking for guidence how to move forward so that i can apply my knowledge future based on mistakes i made here. Thanks for your time and help
int getMinConnectionChange(vector<int> connection) {
// Idea: Get number of strongly connected components.
int numberOfVertices = connection.size();
for(int idx = 0; idx < numberOfVertices; idx++) {
cout << idx+1 <<":"<< connection[idx] << endl;
}
stack<int> stkVertices;
map<int, bool> mpVertexVisited; //is vertex visited.think this as a chalk mark for nodes visited.
int numOFSCCs = 0;
int currTime = 1;
for (int vertexId = 0; vertexId < numberOfVertices; vertexId++) {
// check if node is already visited.
if (mpVertexVisited.find(vertexId+1) == mpVertexVisited.end()) {
numOFSCCs++;
mpVertexVisited.insert(make_pair(vertexId+1, true));
stkVertices.push(vertexId+1);
currTime++;
while (!stkVertices.empty()) {
int iCurrentVertex = stkVertices.top();
stkVertices.pop();
// get adjacent vertices. In this excercise we have only one neighbour. i.e., edge
int neighbourVertexId = connection[iCurrentVertex-1];
// if vertex is already visisted, don't insert in to stack.
if (mpVertexVisited.find(neighbourVertexId) != mpVertexVisited.end()) {
continue;
}
mpVertexVisited.insert(make_pair(neighbourVertexId, true));
stkVertices.push(neighbourVertexId);
} // while loop
} // if condition m_mapVrtxTimes.find(*itr) == m_mapVrtxTimes.end()
} // for loop of vertices
return numOFSCCs - 1;
}
This is a problem that I just solved and would like to share the solution.
The problem can be solved with union-find.
Two main observation:
The number of edges that has to be changed is the number of components - 1 (not necessarily strongly connected) Thus, union-find is handy here for finding the number of components
Second observation is that some component doesn't have terminating node, consider 1<->2, in other words, a cycle exist. We can detect whether there exists a terminating node if some node doesn't have an outgoing edge.
If all components have a cycle, it means that we need to change every component instead of a number of components - 1. This is to make it such that the graph will have a terminating point.
Code:
struct UF {
vector<int> p, rank, size;
int cnt;
UF(int N) {
p = rank = size = vector<int>(N, 1);
for (int i = 0; i < N; i++) p[i] = i;
cnt = N;
}
int find(int i) {
return p[i] == i ? i : p[i] = find(p[i]);
}
bool connected(int i, int j) {
return find(i) == find(j);
}
void join(int i, int j) {
if (connected(i, j)) return;
int x = find(i), y = find(j);
cnt--;
if (rank[x] > rank[y]) {
p[y] = x;
size[x] += size[y];
} else {
p[x] = y;
size[y] += size[x];
if (rank[x] == rank[y]) rank[y]++;
}
}
};
int getMinConnectionChange(vector<int> connection) {
int nonCycle = 0;
int n = connection.size();
UF uf(n);
for(int i=0;i<n;i++) {
int to = connection[i] - 1;
if(to == i) nonCycle++;
else uf.join(i, to);
}
int components = uf.cnt;
int countCycle = uf.cnt - nonCycle;
int res = components - 1;
if(countCycle == components) res++; // all components have cycle
return res;
}
TL;DR: you can view this as looking for a minimal spanning arborescence problem.
More precisely, add a node for each server, and another one called "Terminate".
Make a complete graph (each node is linked to every other one) and set as cost 0 for the edges corresponding to your input, 1 for the other ones.
You can use for example Edmond's algorithm to solve this.
There are N network nodes, labelled 1 to N.
Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the target node, and w is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? If it is impossible, return -1.
here is my code.. however it is giving wrong answer
class Solution {
public:
int networkDelayTime(vector <vector<int>> ×, int N, int K) {
vector<int> time(N + 1);
vector<int> visited(N + 1, 0);
vector < vector < pair < int, int >> > graph(N + 1);
for (int i = 0; i < times.size(); i++) {
graph[times[i][0]].push_back(make_pair(times[i][1], times[i][2]));
}
queue <pair<int, int>> q;
q.push(make_pair(K, 0));
visited[K] = 1;
time[K] = 0;
while (!q.empty()) {
int end = q.front().first;
int duration = q.front().second;
q.pop();
for (auto k:graph[end]) {
int first = k.first;
int second = k.second;
if (!visited[first]) {
q.push(make_pair(first, second));
time[first] = duration + second;
visited[first] = 1;
} else {
time[first] = min(time[first], (duration + second));
}
}
}
for (int i = 1; i <= N; i++) {
if (visited[i] == 0) {
return -1;
}
}
sort(time.begin(), time.end());
return time[N];
}
};
I am not able to figure out where I am wrong.
Thanks
This is a text-book application of Dijkstra's algorithm.
Given a node K, this algorithm will fill an array with the minimum distance from K to every other node, so the biggest value in this array will be the total time it takes for the signal to reach every other node.
You can't just use a BFS because it won't necessarily consider a shorter path to a node once it has already found any other path to that node. Dijkstra's algorithm is a modification of the BFS that deals with that. See this example, supposing the initial node is 1, the distances to the other nodes given by BFS and Dijkstra are different:
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)
I'm implementing Dijkstra's algorithm for school and my code keeps messing up. I've followed the pseudo-code on Wikipedia very closely. I implement the graph with a weighted adjacency list in this form so I check neighbours by iterating through the corresponding row.
Here's my graph class, along with my vertex struct.
struct vertex
{
//constructor
vertex(size_t d_arg, size_t n_arg)
{
n = n_arg;
d = d_arg;
}
//member variables, n is name and d is distance
size_t n;
size_t d;
//overloaded operator so I can use std::sort in my priority queue
bool operator<(const vertex& rhs) const
{
return d<rhs.d;
}
};
class graph
{
public:
graph(vector<vector<size_t> > v){ ed = v;};
vector<size_t> dijkstra(size_t src);
bool dfs(size_t src);
private:
//stores my matrix describing the graph
vector<vector<size_t> > ed;
};
The function dfs implements a Depth-first Search to check if the graph's joint. I've got no problems with it. But the function dijkstra, however, gives me the wrong values. This is how it's implemented.
vector<size_t> graph::dijkstra(size_t src)
{
//a vector storing the distances to the vertices and a priority queue
vector<size_t> dist;
dist[src] = 0;
p_q<vertex> q;
//set the distance for the vertices to inphinity, since they're size_t and -1 is largest
for (size_t i = 0; i < ed.size(); i++) {
if(i!=src)
{
dist.push_back(-1);
}
//push the vertices to the priority queue
vertex node(dist[i], i);
q.push(node);
}
//while there's stuff in the queue
while(q.size())
{
//c, the current vertex, becomes the top
vertex c = q.pop();
//iterating through all the neighbours, listed in the adjacency matrix
for(int i = 0; i < ed[0].size(); i++)
{
//alternative distance to i is distance to current and distance between current and i
size_t alt = dist[c.n] + ed[c.n][i];
//if we've found a better distance
if(alt < dist[i])
{
//new distance is alternative distance, and it's pushed into the priority queue
dist[i] = alt;
vertex n(alt, i);
q.push(n);
}
}
}
return dist;
}
I can't see why I'm having trouble. I've debugged with this matrix.
0 3 -1 1
3 0 4 1
-1 4 0 -1
1 1 -1 0
And it didn't visit anything other than vertex 0 and vertex 3.
One of the problems is right at the beginning of graph::dijkstra, when an element of zero-sized array is assigned:
vector<size_t> dist;
dist[src] = 0;
It is OK in pseudo-code, but not in C++. Perhaps you may change like this:
vector<size_t> dist;
for (size_t i = 0; i < ed.size(); i++) {
if(i!=src)
{
dist.push_back(-1);
}
else
{
dist.push_back(0);
}
....
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.