As I was practicing C++ today, I came across a code which finds the shortest path in an unweighted graph using BFS and outputs the length of the path and the vertices it travelled through.
I attempted to change up this code by introducing user input.
First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges.
The next M lines contain two integers, which indicates an undirected edge between two nodes.
I attempted to change the code in accordance to this, but I ran into a number of problems.
The first problem is that if I use gcc, the program will end after the for loop runs once in the main function.
However, if I use clang, the program runs fine. But there is an other issue and it relates to a very specific input.
The following input:
3 3
1 3
1 2
2 3
should return 1, but sometimes (specifically when I enter the input line by line) it returns the message: "Given source and destination are not connected". It is completely random.
The code is below:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[]);
void printShortestDistance(vector<int> adjList[], int s, int dest, int numOfVertices);
int main()
{
int numOfVertices, numOfEdges;
cin >> numOfVertices >> numOfEdges;
vector<int> adjList[numOfVertices];
if (2 <= numOfVertices && numOfVertices <= 1e5 && 1 <= numOfEdges && numOfEdges <= 1e5)
{
for (int i = 0; i < numOfEdges; i++)
{
int node1, node2;
cin >> node1 >> node2;
if ((1 <= node1) && (1 <= node2) && (node1 <= numOfVertices) && (node2 <= numOfVertices) && (node1 != node2))
{
adjList[node1].push_back(node2);
adjList[node2].push_back(node1);
}
else{ return EXIT_FAILURE; }
}
int source = 1;
int dest = numOfVertices;
printShortestDistance(adjList, source, dest, numOfVertices);
}
}
void printShortestDistance(vector<int> adjList[], int source, int dest, int numOfVertices)
{
int pred[numOfVertices];
int dist[numOfVertices];
if (BFS(adjList, source, dest, numOfVertices, pred, dist) == false)
{
cout << "Given source and destination are not connected";
return;
}
vector<int> path;
int crawl = dest;
path.push_back(crawl);
while (pred[crawl] != -1)
{
path.push_back(pred[crawl]);
crawl = pred[crawl];
}
cout << "Shortest path length is : " << dist[dest];
cout << "\nPath is::\n";
for (int i = path.size() - 1; i >= 0; i--)
cout << path[i] << " ";
}
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[])
{
list<int> queue;
bool visited[numOfVertices];
for (int i = 0; i < numOfVertices; i++)
{
visited[i] = false;
dist[i] = INT_MAX;
pred[i] = -1;
}
visited[source] = true;
dist[source] = 0;
queue.push_back(source);
while (!queue.empty())
{
int u = queue.front();
queue.pop_front();
for (int i = 0; i < adjList[u].size(); i++)
{
if (visited[adjList[u][i]] == false)
{
visited[adjList[u][i]] = true;
dist[adjList[u][i]] = dist[u] + 1;
pred[adjList[u][i]] = u;
queue.push_back(adjList[u][i]);
// We stop BFS when we find
// destination.
if (adjList[u][i] == dest)
return true;
}
}
}
return false;
}
"First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges."
This is not a good idea. Humans are terrible at counting, while computers are pretty good at it. So do not make your users count the vertices and edges - they will often get it wrong and cause chaos.
Just input the start and ending nodes of an edge. If a node is already present in the data structure, connect it. If node not already present then add it and then connect it.
You will have much happier users!
I see that you have decided to store your graph in an adjacency list. This is a perfectly reasonable idea, but the snag is that it is quite a challenge to code. This seems to be your first attempt to code a graph theory problem, so I recommend that you use an adjacency matrix instead since it is much easier to code.
For small graphs the difference is insignificant, so you need only consider switching to the more complicate adjacency list when you are working with enormous graphs ( many thousands of nodes )
Remember that vectors in C++ are 0-based.
In your example, numOfVertices and numOfEdges are both 3, so node 3 will lead to out-of-bound access. Either change your input to 0-based node numbers or use node1-1 and node2-1.
See also
Vector going out of bounds without giving error
and the accepted answer.
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.
I have to read in a file to create a weighted graph. The shortest path must be found using input from the file. File will be structured as first line = numVertices and every line below that has 3 numbers given as : 0 1 2 where 0 is start of an edge, 1 is the end of the edge, and 2 is the weight. I've tried implementing an adjacency matrix when creating my graph but have had no luck. Any suggestions would be greatly appreciated.
Have tried restructuring the way I read in my file and have also tried adjusting my findShortestPath function.
void createGraph(string file_name) //Function to create a graph based on a file, whose name is file_name.
{
ifstream f(file_name);
if (f.fail())
{
return;
}
string line;
getline(f, line);
int num = stoi(line);
numVertices = num;
int data[50][50];
string line2;
int num1 = 0, num2 = 0, num3 = 0;
while (!f.eof())
{
f >> num1;
f >> num2;
f >> line2;
num3 = stoi(line2);
data[num1][num2] = num3;
}
}
//////////////////shortest path function
string findShortestPath(int start, int end)
{
int data[numVertices][numVertices];
int dist[numVertices];
bool sptSet[numVertices];
int parent[numVertices];
for (int i = 0; i < numVertices; i++)
{
parent[0] = -1;
dist[i] = INT_MAX;
sptSet[i] = false;
}
dist[start] = 0;
for (int count = 0; count < numVertices - 1; count++)
{
int u = minDistance(dist, sptSet);
sptSet[u] = true;
if (sptSet[u] == end)
break;
for (int v = 0; v < numVertices; v++)
if (!sptSet[v] && data[u][v] && dist[u] + data[u][v] < dist[v])
{
parent[numVertices] = end;
dist[v] = dist[u] + data[u][v];
}
}
printSolution(parent);
Output is not outputting shortest path and is printing random numbers.
In your findShortestPath function data[numVertices][numVertices] is not the same as the data variable in your createGraph function.
Look at this https://www.geeksforgeeks.org/scope-of-variables-in-c/ or try finding other sources on scope of variables.
In your function findShortestPath you have declared a local array called data, which is supposed to store the adjacency matrix data. However, you have never written any data into it! Consider passing the matrix as a function argument. Your function signature should look something like this:
findShortestPath(int** data, int numVertices, int start, int end)
Also, avoid using VLA as it is not part of the standard. Consider creating a two dimensional array on the heap using new. (and don't forget to do delete[] after you are done!)
Or you can use std::vector<std::vector<int>>, if you don't want to manage your array's lifetime manually.
Given a directed graph with parallel edges, I need to find the number of paths between the first and the last node in the input. Traversal of the same edge multiple times is allowed and parallel edges count as distinct paths.
The way I approached the problem is considering the number of paths between node s and node t that are no longer than k. The longest simple path in a graph with N nodes has N-1 vertices, thus if there are no cycles, path_count(s,t,n-1) and path_count(s,t,3n-3) should be equal. 3n -3 is basically a traversal of the longest simple path, a second traversal to the origin and yet another one to the target, establishing a cycle by reaching the target twice.
I have written some code to implement this. I use a vector called lookup to store intermediate results to speed things up. Here's what I've come up with:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
vector<vector<int>> lookup;
int paths_count(vector<vector<int>> & graph, int k, int start, int dest)
{
if (lookup[k][start] != -1)
return lookup[k][start];
int result =0;
if (k==1 && graph[start][dest]) //last hop, ends on target vertex
{
lookup[k][start] = graph[start][dest];
return graph[start][dest];
}
if (k==1) { // last hop, didn't reach target vertex
lookup[k][start]=0;
return 0;
}
for (int i=1; i < graph.size(); i++) {
if (graph[start][i]>0) {
if (i==dest) // assume no outbound edges from destination vertex
result+=graph[start][dest];
else {
// paths from i to dest
int pc =paths_count(graph, k-1, i, dest);
/*
total number of paths from start to dest through i is the
number of paths from i to dest
times the number of edges from start to i
*/
result+=graph[start][i]*pc;
}
}
}
lookup[k][start]=result;
return result;
}
int main() {
int n, m,x,y;
vector<vector<int>> graph;
cin >> n >>m;
graph.resize(n+1);
lookup.resize(3*n - 2);
for (int i=0; i < 3*n-2;++i)
for (int j=0; j < n+1;++j)
lookup[i].push_back(-1);
for (int i=0; i < n+1; ++i)
graph[i].resize(n+1);
for (int i=0; i <m;++i) {
cin >> x >>y;
graph[x][y]+=1;
}
int count1 = paths_count(graph,n-1,1,n);
int count2 = paths_count(graph,3*n-3,1,n);
if (count1 != count2)
cout << "INFINITE PATHS";
else
cout << count1;
return 0;
}
the issue is that I have some given test cases, and some test cases I've written myself. My solution succeeds on my test cases and on some small-ish test cases but fails on the larges ones which I cannot manually debug (100 nodes, thousands of vertices). I've also tried a different idea with DFS that failed on the same test cases, leading me to believe that I fundamentally don't understand something about this problem. Any ideas?
Thank you.
I have an input file that I'm trying to parse in order to perform operations like DFS, Best-First Search, A* search, etc.
It looks like this:
| The vertical bar denotes comments. Ignore.
|
| The first non-comment line contains N, the number of nodes in the graph.
5
| The second non-comment line contains the unique start node.
0
| The third non-comment line contains a single goal node.
3
| The fourth non-comment line specifies the number of heuristics.
1
| The fifth non-comment line starts the edge-cost adjacency matrix. [i,j] in the matrix represents the weight of the edge from node i to node j.
* 1 2 * *
* * 3 * *
* * * 5 4
* * * * *
* * * * *
| After the adjacency matrix, the heuristic evaluation vectors are given,
| where each row containing the heuristic value h(n) for a node n
3
6
1
0
For the code, I created a class for the nodes in the Adjacency list and a class for the graph. I have managed to parse all the input except the last one, the heuristic evaluation numbers. Here is my code:
class AdjListNode
{
private:
int v; // vertex or node number.
int weight; // weight on edge to reach a particular vertex.
int h; // a heuristic number for every node.
public:
AdjListNode(int _v, int _w) { v = _v; weight = _w;}
int getV() { return v;} // return the vertex number
int getWeight() {return weight;}
void setH(int _h) { h = _h;}
int getH() { return h;}
};
class Graph
{
private:
int V; // Total number of nodes/vertices in the graph
list<AdjListNode> *adj; // a list for storing all the nodes
//A helper function for Depth-First Search DFS.
bool DFSUtil(int v, bool visited[], int goal, int cost);
public:
Graph(int V);
void DFS(int v, int goal); // Depth First Search
void addEdge(int i, int j, char* val); // Add edge between i and j
// of weight val.
//Print the adjacency list;
void printList();
};
void Graph::printList()
{
list<AdjListNode>::iterator i;
for (int j = 0; j < V; j++)
{
for (i = adj[j].begin(); i != adj[j].end(); i++)
{
AdjListNode node = *i;
cout << node.getV() << " ";
}
cout << endl;
}
}
Graph::Graph(int V)
{
this->V = V;
adj = new list<AdjListNode>[V];
}
void Graph::addEdge(int u, int v, char* val)
{
int weight = atoi(val);
AdjListNode node(v, weight);
adj[u].push_back(node);
}
bool Graph::DFSUtil(int v, bool visited[], int goal, int cost)
{
visited[v] = true;
if (v == goal)
{
cout << "cost is : " << cost << endl;
cout << "path is : ";
return true;
}
list<AdjListNode>:: iterator i;
for (i = adj[v].begin(); i != adj[v].end(); i++)
{
AdjListNode node = *i;
if (!visited[node.getV()])
{
if (DFSUtil(node.getV(), visited, goal, cost + node.getWeight()))
{
cout << node.getV() << " " ;
return true;
}
}
}
return false;
}
void Graph::DFS(int v, int goal)
{
bool *visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
int cost = 0;
DFSUtil(v, visited, goal, cost);
}
Here is the main() function where I am trying to parse all the values from the input file:
int main()
{
string line; // read every line into this variable
int argCount = 0; // keep track of 4 arguments (V, start, goal, and
// J)
int V, start, goal, J; // V is number of nodes, start is the start
// node, goal is goal node, J is just a
// number (ignore for now)
//input for nodes, start, goal, and J
while (getline(cin, line) && argCount < 4)
{
if (line[0] == '|') // reject the line and continue if the line
continue; // starts with '|'
// convert the line which is a string into int and store in
// respective variables
switch (argCount)
{
case 0: V = stoi(line);
argCount++;
break;
case 1: start = stoi(line);
argCount++;
break;
case 2: goal = stoi(line);
argCount++;
break;
case 3: J = stoi(line);
argCount++;
break;
}
}
Graph g(V); // create a Graph of 'V' nodes or vertices.
//ignore lines starting with '|'
while (getline(cin, line))
{
if (line[0] == '|')
continue;
break;
}
// after the above loop, line contains the first row of the matrix
// buffer array for taking in weight from stringstream.
char weight[100];
//parse first row of the matrix
stringstream ss;
ss << line;
for (int v = 0; v < V; v++)
{
ss.getline(weight, 6, ' '); // get the value into weight,
// ' '(whitespace) is a delimiter.
if (weight[0] != '*') // ignore if weight is '*'
g.addEdge(0, v, weight);// call addEdge() to add edge
// between 0 (because this is the
// first row) and v and assign
// weight.
}
ss << ""; // reset stringstream.
ss.clear();
// parse rest of the rows of the matrix. first row already parsed
// above
for (int u = 1; u < V; u++) // u is row, starting from 1.
{ getline(cin, line); // take the whole line
ss.clear();
ss.str("");
ss << line; // put the line in stringstream
int v = 0; // v is column number.
while (ss >> weight)
{
if (weight[0] != '*')
g.addEdge(u, v, weight); // add Edge between u and v.
v++; // increment column number.
}
}
//ignore lines starting with '|' else set the h value for the nodes
// THIS IS WHERE I AM STUCK. I NEED TO TAKE IN THE H VALUES AND
// ASSOCIATE THEM WITH THEIR NODES WHICH ARE ALREADY CREATED.
int n = 0;
list<AdjListNode>::iterator i;
while (getline(cin, line))
{
//cout << line;
if (line[0] == '|')
continue;
int h = stoi(line);
}
cout << "The adjacency list is : " << endl;
g.printList();
g.DFS(start, goal);
cout << endl;
return 0;
}
How can I take in the h values and associate them with the correct nodes? I am confused because I am calling the addEdge() function to add the edges between the nodes before taking in the h values. I tried to use getters and setters but I am not able to implement those concepts because I am a novice.
Thanks!
EDIT 1 : Added comments.
EDIT 2 : The class structure is supposed to be this:
For the adjacency list node class, AdjListNode:
Each node has 3 attributes; an integer v to identify it, a weight for calculating the cost to reach that node, and a heuristic value h which I am confused on how to assign because I have already called the constructor and would be parsing the h values from the input file later.
I know I am missing some elementary concept here.
For the class Graph:
A list stores all the AdjListNode type nodes as an adjacency list. I need to perform A* search on this.
EDIT: The core of your difficulty here is found in your class structure. Think about your goal - you want to associate an h with an edge, correct? The word "associate" means that you need some sort of data structure in your class(es) that allows you to do just that.
There are a few structures to choose from: tuples and structs are two possibilities. If you store the structure in your list, you can enter all of edges, and then step through and enter all of the h values.
Another possibility is to use a union to allow you to store both types of values in the same list. This will be more difficult, but may accomplish your goal.
Beyond this, you will need to do the research yourself, here.
--
I know you're new here, so I'll let you know that very few people will just give you the correct code outright, especially on something this complex. Just a heads up.
Second, you're on rather shaky ground if you do not understand your own object structure. I'm having a hard time reading it myself, and I'm a professional. Please, for the love of all things digital, comment your code! What do your various one- or two-letter variables mean...or the ones with the longer but still elusive names? (Don't feel too bad about this...common habit among programmers. Ask anyone here.)
Getters and setters are not a complex matter. Getters simply return the value of a private variable in the class. A setter is a function that accepts an argument, and assigns that argument to a particular private variable in the class, usually after checking for errors.
The best advice I can give you right now is A) comment your code, and B) figure out your code's basic object structure. Literally write (on paper if you have to) the names of your objects, what is stored inside them, what's hidden and what's public, and what they're supposed to do. If you figure that out, you'll probably find your answer on your own. Otherwise, edit your question with that information.
If I see that work - the intended class structure and some good comments - I'll edit with more details on how to fix your code. It's about doing the footwork yourself.
By the way, you have variables hanging out above your scope declarations (in this case, public:) in your headers, which is a no-no.
Here my tryings, and copypastings. But what i must write to find biconnectedcomponent (called block)?
#include <fstream>
#include <vector>
using namespace std;
ifstream cin ("test3.txt");
ofstream cout ("output.txt");
const int l = 6;
int G[l][l];
int MAXN;
int used[l];
int number[l], low[l], counter = 1, kids = 0;
vector <int> block[l];
void BiComp(int curr, int prev) {
int kids = 0;
low[curr] = number[curr] = counter++;
used[curr] = 1;
for(int i = 0; i < MAXN; i++) {
if(G[curr][i] == 1) {
if (i != prev) {
if (used[i] == 0) {
kids++;
block[0].push_back(curr);
block[0].push_back(i);
BiComp(i, curr);
low[curr] = min(low[curr], low[i]);
if(low[i] >= number[curr] && (prev != -1 || kids >= 2)) {
cout << "tochka " << curr + 1 << endl;
}
} else {
block[0].push_back(i);
block[0].push_back(prev);
cout<<block<<endl;
low[curr] = min(low[curr], number[i]);
}
}
}
}
}
void main()
{
MAXN = 6;
for (int i = 0; i < MAXN; i++)
{
for (int j = 0; j < MAXN; j++)
{
cin >> G[i][j];
cout << G[i][j] << " ";
}
cout << endl;
}
//for (int i = 0; i < MAXN; i++) {
//if (number[i] == 0) {
BiComp(0, -1);
//}
//}
}
How can i find by this code, finding cutpoints at the same time blocks???
In graph theory, a biconnected component (or 2-connected component) is a maximal biconnected subgraph.
Ok what comes to my mind is a very brute-force approach that isn't going to scale well, but I also remember reading that finding biconnected components is in fact a hard problem, computationally, so let's just start with it and then see if there's optimizations to be done.
Given a set of N nodes, check for each possible subset of nodes whether they form a biconnected component. Typically, you'll want the biggest component available, so just start with the whole graph, then with all subgraphs of N-1 nodes, N-2, and so on. As soon as you find one solution, you'll know you have found one of the biggest possible size and you can quite. Still, you'll end up checking 2^N subgraphs in the worst case. So start with a loop constructing your graphs to be tested.
To find out if a given graph with K nodes is a biconnected component, loop over all K*(K-1)/2 pairs of nodes and find out if there are two independent paths between them.
In order to find out if two nodes i and j are biconnected, first find all paths between them. For each path, find out if there is an alternative connection to that path. If you find one, you're done for that pair. If not, you've found proof that the graph you're looking at is not biconnected and you can break from all loops but the outer one and test the next graph.
In order to see if there is an alternative connection between i and j, take out all edges you used in the first path, and see if you can find another one. If you can, you're fine with i and j. If you can't, continue with the next path in the initial list of paths you found. If you reach the end of your list of paths without finding one for which an alternative exists when taking out the involved edges, the two nodes are not biconnected and hence the whole graph isn't.
There is a linear run time algorithm for finding all cut points (or cut vertices or articulation points) in a given graph using Depth First Search.
Once you found all the cut points, it's easy to find all of the bicomponents.