Shortest path given beginning and end of a weighted graph - c++

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.

Related

Shortest path in an unweighted graph, using user input in C++

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.

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.

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.

Bug in selection sort loop

I need to make a program that will accept a input file of numbers(integer.txt) which will be sorted one number per line, into a vector, then use a selection sort algorithm to sort the numbers in descending order and write them to the output file (sorted.txt). I'm quite sure something is wrong in my selectionSort() function that is causing the loop not to get the right values, because after tested with cout I get vastly improper output. I'm sure it's a beginning programmer's goof.
vector<string> getNumbers()
{
vector<string> numberList;
ifstream inputFile ("integer.txt");
string pushToVector;
while (inputFile >> pushToVector)
{
numberList.push_back(pushToVector);
}
return numberList;
}
vector<string> selectionSort()
{
vector<string> showNumbers = getNumbers();
int vectorMax = showNumbers.size();
int vectorRange = (showNumbers.size() - 1);
int i, j, iMin;
for (j = 0; j < vectorMax; j++)
{
iMin = j;
for( i = j; i < vectorMax; i++)
{
if(showNumbers[i] < showNumbers[iMin])
{
iMin = i;
}
}
if (iMin != j)
{
showNumbers[j] = showNumbers [iMin];
}
}
return showNumbers;
}
void vectorToFile()
{
vector<string> sortedVector = selectionSort();
int vectorSize = sortedVector.size();
ofstream writeTo;
writeTo.open("sorted.txt");
int i = 0;
while (writeTo.is_open())
{
while (i < vectorSize)
{
writeTo << sortedVector[i] << endl;
i += 1;
}
writeTo.close();
}
return;
}
int main()
{
vectorToFile();
}
vectorRange defined but not used.
In your selectionSort(), the only command that changes the vector is:
showNumbers[j] = showNumbers [iMin];
Every time control reaches that line, you overwrite an element of the vector.
You must learn to swap two values, before you even think about sorting a vector.
Also, your functions are over-coupled. If all you want to fix is selectionSort, then you should be able to post that plus a main that calls it with some test data and displays the result, but no, your functions all call each other. Learn to decouple.
Also your variable names are awful.

Degree: Polynomial Class (Odd Cases for User Input Expected)

I have a polynomial class that prompts the user to enter values to be put into a vector of integers (vector<int> vect_poly). I'm trying to think of a way to detect the degree of the polynomial for cases where the user does something like this in the while loop:
0↵0↵0↵0↵4↵0↵0↵0↵0 ← x^4 (degree=4)
(OR)
0↵0↵0↵0↵0↵0↵0↵0↵0 ← (degree=0)
(OR)
4↵0↵0↵0↵0↵0↵0↵0↵0 ← x^0 (degree=0)
(OR)
0↵0↵0↵0↵0↵0↵0↵0↵4 ← x^8 (degree=8)
I'm really just looking for a slick algorithm.
What about this:
int degree()
{
int d = 0;
for ( int i = 0; i < 100; i++ )
if ( coef[i] != 0 ) d = i;
return d;
}
If u have this vector where user have enter the value of coefficient, you can traverse the vector from index 0 to the last element (Assuming user will enter the value of coefficient in correct order), and just save the value of last index whose value is not zero.
int degreeOfPolynomial=0;
for(int i=0 ; i < vect_poly.size() ; i++)
{
if(vect_poly[i] != 0)
degreeOfPolynomial = i;
}
After execution of above part of code, degreeOfPolynomial will store right value of degree of polynomial.
Why not just keep track of it?
std::vector<int> polynomial;
int degree = 0;
int inputs = 0;
int coefficient;
while (std::cin >> coefficient)
{
polynomial.push_back(coefficient);
if (coefficient != 0)
{
degree = inputs;
}
inputs++;
}
I see two options:
Simply copy the input into the vector, then search for the last non-zero and truncate the vector after that.
Copy input into a temporary vector, and each time a non-zero is entered, move-append the temporary vector to vect_poly, like this:
std::vector<int> temp;
int n;
while (std::cin >> n) {
temp.push_back(n);
if (n != 0) {
vect_poly.insert(vect_poly.end(), temp.begin(), temp.end());
temp.clear();
}
}
That way, you get everything except the trailing zero sequence in vect_poly.
EDIT
3. You can also keep the 0s in a counter:
int n;
size_t zeroes = 0;
while (std::cin >> n) {
if (n == 0) {
++zeroes;
} else {
vect_poly.insert(vect_poly.end(), zeroes, 0);
vect_poly.push_back(n);
zeroes = 0;
}
}
You can use a local variable to keep track of the max, and each time the user presses enter, you compare their input to the current max value.
int max=0;
while(1)
{
int input=0;
std::cin>>input;
if(input>max)
{
max=input;
}
}
Of course with some breakout condition so the loop doesn't run forever. You could try to mess with the ternary operator at the if statement, but I see little value in that.
EDIT: if you want to know the last set value (ie degree) of a previously generated but essentially random vector as quickly as possible, run a loop like this:
int max=0;
for(int k= myvec.size()-1; k>=0; k--)
{
if(myvec[k]>0)
{
max=k;
break;
}
}