Dijkstra's algorithm not working - c++

I'm creating a game for a school project, and I want to use Dijkstra's algorithm as part of an AI for the objects the player needs to dodge.
So I have a graph (an adjacency matrix) and I want to use Dijkstra to get the path from each object to the player, but right now when I call the algorithm, it will not find the player if the player comes after the object.
In my understanding, Dijkstra's algorithm should visit all of the nodes until it finds the destination, but it doesn't in my case.
Here's what my algorithm looks like so far:
Node* Graph::DijkstrasAlgorithm(Node* sNode, Node* dNode){
std::cout<<"Hello Dijkstra!!"<<std::endl;
for(unsigned int i = 0; i < this->nodeList.size(); ++i){
nodeList.at(i)->setDistance(INT_MAX);
nodeList.at(i)->setVisited(false);
}
std::cout<<"everything is set"<<std::endl;
sNode->setDistance(0);
int numberVisited = 0;
Node* u = new Node();
std::cout<<"before while lus"<<std::endl;
while(numberVisited < numberOfNodes){
u->setDistance(INT_MAX);
for(unsigned int j = 0; j < this->nodeList.size(); ++j){
if((u->getDistance() > this->nodeList.at(j)->getDistance()) && !this->nodeList.at(j)->isVisited() ){
u = this->nodeList.at(j);
u->setVisited(true);
numberVisited++;
}
}
std::cout<<u->getNodeName()<<"=="<<dNode->getNodeName()<<std::endl;
if((u == dNode) || (u->getDistance() == INT_MAX)){
std::cout<<"true"<<std::endl;
break;
}
for(int k = 0; k < u->numberOfneighbors(); ++k){
if(!u->getNeighbors(k)->isVisited())
{
// std::cout<<u->getDistance()<<std::endl;
int alt = u->getDistance() + 1;
if( alt < u->getNeighbors(k)->getDistance()){
u->getNeighbors(k)->setDistance(alt);
u->getNeighbors(k)->setPrevious(u);
}
}
}
}
std::vector<Node* > stack;
u = dNode;
while(u->getPrevious() != NULL){
stack.insert(stack.begin(), u);
u = u->getPrevious();
}
if(!stack.empty())
return stack.at(0);
else
return sNode;
}
In this case, dNode is the destination node, and sNode is the start node.
Does anyone know what I'm doing wrong?

In Dijkstra algorithm you mark as visited only the node to which the shortest augmenting path points to. I can see an error you make here:
u = this->nodeList.at(j);
u->setVisited(true);
Don't mark the nodes as visited immediately.
Mark as visited only the node u will point to after the cycle
for(unsigned int j = 0; j < this->nodeList.size(); ++j){
Otherwise for every improvement you will mark the node as visited, not even processing all of them.

It does not even look like Dijkstra algorithm.
To implement Dijkstra algorithms you need to maintain two lists of nodes:
A list of searched nodes
A SORTED list of edge nodes.
Each node in this list has the cost to reach this location.
I see neither of these lists in your code.
You are also storing the cost in the node. This will not work as the cost to reach a node will depend on the route (unless you can store multiple costs associated with node).
I would expect the code to look like this:
// pseudo code.
// Note all features used are strictly available
//
Node* Graph::DijkstrasAlgorithm(Node* sNode, Node* dNode)
{
std::list<Node*> searchedNodes;
std::list<std::pair<Node*, cost>> edgeNodes;
edgeNodes.push_sorted(sNode, 0);
while(!edgeNodes.empty())
{
std::pair<Node*, cost> next = edgeNodes.pop_front();
searchedNodes.push_back(next.first);
if (next.first == dnode)
{ // We found the route
return STUFF;
}
for(Edge* edge, next.first->getEdges())
{
if (searchedNodes.find(edge->dst) != searchedNodes.end())
{ continue;
}
edgeNodes.push_sorted(dest.dst, next.second + edge->cost);
}
}
}

Related

How i make bfs more efficient in cpp

I have problem in unweighted undirected graph the question ask if any path between two point in binary matrix, the user insert the matrix and the cell in matrix to test
bool BFS(vector<vector<int>>mat, Point src, Point dest,int n,int m)
{
if (!mat[src.x][src.y] || !mat[dest.x][dest.y])
return 0;
bool visited[n][m];
memset(visited, false, sizeof visited);
visited[src.x][src.y] = true;
queue<queueNode> q;
queueNode s = {src};
q.push(s);
while (!q.empty())
{
queueNode curr = q.front();
Point pt = curr.pt;
if (pt.x == dest.x && pt.y == dest.y)
return 1;
q.pop();
for (int i = 0; i < 8; i++)
{
int row = pt.x + rowNum[i];
int col = pt.y + colNum[i];
if (isValid(row, col,n,m) && mat[row][col] &&
!visited[row][col])
{
visited[row][col] = true;
queueNode Adjcell = {row, col};
q.push(Adjcell);
}
}
}
return 0;
}
In hacker rank some test not work properly because timeout.
Any one can help please?
Idea 1: if what you need is find out "if there is a path", then it is really not necessary to use a BFS algorithm. There is overhead, a lot of overhead in queue operation.
Just do a nested loop, for every A,B,C where [A,B] is connect, and [B,C] is connected, mark C[A,c] as well. Sort of like dynamic programming. And finally return the connection between the two input nodes.
BFS is only needed when there exists some choice that are better than others. It is not the case in this problem.

graph rerouting algorithm hacker rank

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.

BFS solution giving wrong answer to network time problem

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>> &times, 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:

Traversing to find a vertex in node and returns index

I'm working with tree decomposition and I'm trying to find a vertex in the tree nodes.
I want to return the index of that node if vertex is found. I'm trying to traverse the tree in a DFS manner. I was able to traverse all the nodes, but once the node with vertex is found its not returning the index.
Below is what i tried. Can someone point out where am i going wrong?
Node* Tree::traversing(Node* node, int v) {
vector<Node*> s;
s.push_back(node);
while(!s.empty()) {
Node* nn = s.back();
s.pop_back();
int i = nn->point_in_bag(v);
if(i != -1) { return nn;}
for(int i=0; i<node->children.size(); i++) {
Node* n = node->children[i];
s.push_back(n);
}
}
}
The function point_in_bag returns positive integer if found and -1 if vertex not found.
I got it!!! You just need to change the code:
for(int i=0; i<node->children.size(); i++)
to:
for(int i=0; i< nn->children.size(); i++)
and also in the body. Do you know why?

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.