How i make bfs more efficient in cpp - c++

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.

Related

Google Kickstart Round C: Stable Wall, Wrong Answer

This is the link to the problem here
We have to tell the order in which the letters(like bricks) have to be laid in order for the wall to be stable. ie; for example if the input is
ZOAAMM
ZOAOMM
ZOOOOM
ZZZZOM
Then if I lay 'A's first then they will fall to the ground since in order to lay the letter 'A' I need to lay the letters 'Z' and 'O' first.
If I lay all O's first then they will also fall on the ground since some of the O's depend on the 'Z' below to be laid first.
The answer for the above is 'ZOMA' or 'ZOAM' both are valid answers. If it's not possible then we should print -1.
What I did in my code is that I first made a graph. For the example above, the graph will be O-> A since A depends on O. O->M since M also depends on O. Z->O since O depends on Z.
Then if there is a cycle in the graph then that means it is not possible to lay the wall so I print -1
If there is no cycle then the answer exists, and to get the answer I do a topological sort.
All the example test cases passed, but when I submit, I get a wrong answer. I don't know which test case could be failing. Can you let me know any case which my code is failing for please.
#include<bits/stdc++.h>
using namespace std;
vector<int>adj[26]; // adjacency list to store the graph
int n,m; // n rows each with a string of size m
string s[30];
bool vis[26]; //for topological sort
int visited[26];//for cycle detection
stack <char> mystack;
bool flag = 0;
void cycledfs(int node) // returns -1 if cycle detected
{
if(visited[node] == -1)
{
flag = 1;
return;
}
visited[node] = -1;
for(int i = 0; i < adj[node].size(); i++)
{
if(visited[adj[node][i]] != 1)
{
cycledfs(adj[node][i]);
}
}
visited[node] = 1;
}
void dfs(int node) // if cycle is not detected we do the topological sorting
{
if(!vis[node])
{
vis[node] = 1;
for(int i = 0; i < adj[node].size(); i++)
{
if(!vis[adj[node][i]])
dfs(adj[node][i]);
}
mystack.push(node+'A');
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
set <char> t; // set to store all the unique letters which are my vertices of the graph
for(int i = 0; i <n; i++)
{
cin>>s[i];
for(int j = 0; s[i][j]!='\0';j++)
t.insert(s[i][j]);
if(i)
{
for(int j = 0; s[i][j]!='\0';j++)//to check if the brick above me is different from me. Also making sure no duplicates in the graph.
{
auto it = find(adj[s[i][j]-'A'].begin(), adj[s[i][j]-'A'].end(), (s[i-1][j]-'A'));
if(((s[i][j]-'A') != (s[i-1][j]-'A')) &&(it==adj[s[i][j]-'A'].end()))
adj[s[i][j]-'A'].push_back((s[i-1][j]-'A'));
}
}
}
//initializing stuff
flag = 0;
memset(visited, 0, sizeof(visited));
memset(vis, 0, sizeof(vis));
for(char i: t)//CYCLE CHECKING
{
//cout<<(i-'A')<<"\n";
if(visited[i-'A'] == 0)
cycledfs(i-'A');
if(flag)
break;
}
if(flag)
cout<<"-1\n";
else //doing topological sort if no cycle
{
string result ="";
for(char x: t)
dfs(x-'A');
while(!mystack.empty())
{
char ans = mystack.top();
result.push_back(ans);
mystack.pop();
}
cout<<result<<"\n";
}
for(int i = 0; i < 26; i++) //clearing adj list
adj[i].clear();
}
}

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:

Dijkstra algorithm with Adjacency list Undirected Graph

I'm trying to write a method that would find the shortest path length from one vertex to another, using Dijkstra algorithm. But it doesn't give a correct output. Could you give some advice as to where the problem is?
unsigned distDIJKSTRA(unsigned vert1, unsigned vert2)
{
vector<Vertex3*> pq;
Vertex3* v;
unsigned distance = UINT_MAX;
for (unsigned i = 0; i < vertices.size(); i++)
{
if (vertices[i]->value == vert1)
v = new Vertex3(vertices[i], 0);
else
v = new Vertex3(vertices[i], distance);
pq.push_back(v);
}
make_heap(pq.begin(), pq.end(), lowerPrior);
unsigned newDist;
while (!pq.empty())
{
Vertex3* currV = pq.front();
// If the destination is reached
if (currV->vert->value == vert2)
return currV->dist;
pop_heap(pq.begin(), pq.end(), lowerPrior);
pq.pop_back();
// Checking if the route through currV is shorter
for (unsigned i = 0; i < currV->vert->adjList.size(); i++)
{
Vertex3* nextV = nullptr;
for (unsigned j = 0; j < pq.size(); j++)
if (pq[j]->vert == currV->vert->adjList[i]) {
nextV = pq[j];
break;
}
if (nextV != nullptr)
{
newDist = currV->dist + getWeight(currV->vert, nextV->vert);
if (newDist < nextV->dist)
nextV->dist = newDist;
}
else
continue;
}
sort_heap(pq.begin(), pq.end(), lowerPrior);
}
return UINT_MAX;
}
After updating the distances, your vector won't be a heap anymore. Further more, calling sort_heap in itself would also drop the heap property, instead of fixing it. (See http://en.cppreference.com/w/cpp/algorithm/sort_heap)
Call make_heap instead.
Also note the memory leak: you never deallocate the memory allocated for the Vertex3 objects.

Dijkstra's algorithm not working

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);
}
}
}