Using Dijkstra algorithm to compute shortest path between two nodes - c++

I am new in C++. I am trying to compute the path to travel from node start to node end using Dijkstra algorithm. I am pretty sure I am computing the shortest path in the correct way but for some reason I can't store it in my traceBack vector. It would be really helpful if anyone would help me pointing my mistake here.
My function descriptions and the part of the code where I am computing the shortest path is the following:
The function find_connected_nodes(int x) returns only the nodes connected to the given node.
the function find_travel_time(int x, int y) returns the time to travel from x to y.
void dijkstra(int start, int end) {
vector <unsigned> visited(getNumberOfNodes(), 0);
vector <double> time_weight(getNumberOfNodes(), 99999); //99999 to represent not connected
int inNode = start, pathNode = _end, nextnode = 0;
double min; //will use min to compare time between edges
vector<unsigned> traceBack(getNumberOfNodes(), inNode); //traceBack to contain the path from start to end
time_weight[inNode] = 0;
visited[inNode] = 1;
vector<unsigned> x = find_connected_nodes(start);
if (!x.empty()) {
for (unsigned i = 0; i < x.size(); i++) {
time_weight[x[i]] = find_travel_time(start, x[i]));
}
}
for (int i = 0; i < getNumberOfNodes(); i++) {
min = 99999;
for (int j = 0; j < x.size(); j++) {
if (min > time_weight[x[j]] && visited[x[j]] != 1) {
min = time_weight[x[j]];
nextnode = x[j];
}
}
visited[nextnode] = 1;
for (int j = 0; j < x.size(); j++) {
if (visited[x[j]] != 1) {
if (min + find_travel_time(nextnode, x[j]))<time_weight[x[j]]) {
time_weight[x[j]] = min + find_travel_time(nextnode, x[j]));
traceBack[x[j]] = nextnode;
}
}
}
x = find_connected_nodes(nextnode);
}
int j;
cout << "Path = " << pathNode;
j = pathNode;
do {
j = traceBack[j];
cout << "<-" << j;
} while (j != inNode);
}

Not a complete solution to your problem, because it’s homework and you’ll want to solve it on your own, but here is an example of how to solve the same kind of design problem you’re dealing with:
#include <cstdlib>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::size_t;
std::vector<double> map_squares( const std::vector<double>& inputs )
/* Maps the square function onto the inputs. That is, returns a vector whose
* elements are the squares of the input elements.
*/
{
const size_t size = inputs.size(); // The number of inputs, and outputs.
std::vector<double> outputs(size); // We will return this.
/* (Actually, we will return a copy of the vector, and then the compiler will
* optimize the copy so it doesn't have to copy every element, just a single
* reference to the data in the vector. You'll learn more about how that
* works, and how to write classes like that yourself, in due time.)
*/
for ( size_t i = 0; i < size; ++i ) {
outputs[i] = inputs[i]*inputs[i];
}
outputs.shrink_to_fit(); // Maybe save a few bytes of memory.
return outputs;
}
std::ostream& operator<<( std::ostream& os, const std::vector<double>& v )
// Boilerplate to serialize and print a vector to a stream.
{
const size_t size = v.size();
os << '[';
if (size > 0)
os << v[0];
for ( size_t i = 1; i < size; ++i )
os << ',' << v[i];
os << ']';
return os;
}
int main(void)
{
// Out inputs:
const std::vector<double> raw_numbers = {4,2,1,0.5,0.25};
// Our results:
const std::vector<double> squares = map_squares(raw_numbers);
// Output: "[16,4,1,0.25,0.0625]"
cout << squares << endl;
return EXIT_SUCCESS;
}

Related

Trying to implement Durand-Kerner-Method in C++ using Matrices

My implementation of the Durand-Kerner-Method (https://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method) does not seem to work. I believe (see following code) that I am not calculating new approximation correctly in the algorithm part itself. I cannot seem to be able to fix the problem. Very grateful for any advice.
#include <complex>
#include <cmath>
#include <vector>
#include <iostream>
#include "DurandKernerWeierstrass.h"
using namespace std;
using Complex = complex<double>;
using vec = vector<Complex>;
using Matrix = vector<vector<Complex>>;
//PRE: Recieves input value of polynomial, degree and coefficients
//POST: Outputs y(x) value
Complex Polynomial(vec Z, int n, Complex x) {
Complex y = pow(x, n);
for (int i = 0; i < n; i++){
y += Z[i] * pow(x, (n - i - 1));
}
return y;
}
/*PRE: Takes a test value, degree of polynomial, vector of coefficients and the desired
precision of polynomial roots to calculate the roots*/
//POST: Outputs the roots of Polynomial
Matrix roots(vec Z, int n, int iterations, const double precision) {
Complex z = Complex(0.4, 0.9);
Matrix P(iterations, vec(n, 0));
Complex w;
//Creating Matrix with initial starting values
for (int i = 0; i < n; i++) {
P[0][i] = pow(z, i);
}
//Durand Kerner Algorithm
for (int col = 0; col < iterations; col++) {
*//I believe this is the point where everything is going wrong*
for (int row = 0; row < n; row++) {
Complex g = Polynomial(Z, n, P[col][row]);
for (int k = 0; k < n; k++) {
if (k != row) {
g = g / (P[col][row] - P[col][k]);
}
}
P[col][row] -= g;
}
return P;
}
}
The following Code is the code I am using to test the function:
int main() {
//Initializing section
vec A = {1, -3, 3,-5 };
int n = 3;
int iterations = 10;
const double precision = 1.0e-10;
Matrix p = roots(A, n, iterations,precision);
for (int i = 0; i < iterations; i++) {
for (int j = 0; j < n; j++) {
cout << "p[" << i << "][" << j << "] = " << p[i][j] << " ";
}
cout << endl;
}
return 0;
}
Important to note the Durand-Kerner-Algorithm is connected to a header file which is not included in this code.
Your problem is that you do not transcribe the new values into the next data record with index col+1. Thus in the next loop you start again with a data set of zero entries. Change to
P[col+1][row] = P[col][row] - g;
If you want to use the new improved approximation immediately for all following approximations, then use
P[col+1][row] = (P[col][row] -= g);
Then the data sets all contain the next approximations, especially the first one will no longer contain the initially set powers.

Selection Sort doesn't catch duplicate numbers

What i'm trying to do is implement a simple selection sort algorithm that uses the function minButGreaterThan to find the next smallest number in the array. My problem is if the array has a duplicate number, it gets passed over and left at the end. I've tried changing the controlling if statements to accommodate for this but nothing seems to work. Any advice?
double GradeBook::minButGreaterThan(double x) // - NEEDS TESTING
{
double minButGreaterThan = -1;
for (int i = 0; i < classSize; i++)
{
if (grades[i] > x)
{
minButGreaterThan = grades[i];
break;
}
}
for (int i = 0; i < classSize; i++)
{
if (grades[i] > x && grades[i] <= minButGreaterThan)
minButGreaterThan = grades[i];
}
return minButGreaterThan;
}
void GradeBook::selectionSort() //ascending order -- *DOES NOT WORK WITH DUPLICATE SCORES* - RETEST
{
double min = absoluteMin();
for (int i = 0; i < classSize; i++)
{
if (grades[i] == min)
{
double temp = grades[0];
grades[0] = grades[i];
grades[i] = temp;
break;
}
}
for (int i = 0; i < classSize-1; i++)
{
double next = minButGreaterThan(grades[i]);
for (int n = 1; n <= classSize; n++)
if (grades[n] == next)
{
double temp = grades[n];
grades[n] = grades[i+1];
grades[i+1] = temp;
}
}
}
Should work with duplicates, a selection sort just takes the minimum and moves it to the left, to the "sorted" portion of the array.
This is my implementation:
#include <algorithm>
#include <vector>
using std::swap;
using std::vector;
using std::min_element;
void selectionSort(vector<int> &v) {
for (unsigned int i = 0; i < v.size() - 1; i++) {
auto minElement = min_element(v.begin() + i, v.end());
auto minIndex = minElement - v.begin();
swap(v[i], v[minIndex]);
}
}
You might need to modify it to work with floats. Now, a double floating precision grade (double) seems too much. I think a regular float is OK.

Branch and Bound Algorithm for solving Assignment-probleem

I started doing Branch and Bound Algorithm for assignment problem in C++ and i can't find the right solution. First of all assignment problem example:
Assignment problem
Ok so each person can be assigned to one job, and the idea is to assign each job to one of the person so that all the jobs are done in the quickest way.
Here is my code so far:
#include "Matrix.h"
// Program to solve Job Assignment problem
// using Branch and Bound
#include <limits.h>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
NUM getCost(Matrix& matrix, size_t x, size_t y, vector<bool>& colUsed);
void run(Matrix& matrix, vector<size_t>& assignedJobs);
int main()
{
Matrix matrix;
matrix.setMatrix(N);
matrix.print();
vector<size_t> assignedJobs;
run(matrix, assignedJobs);
cout << assignedJobs[0];
/*
cout << "size:E " << v.size() << endl;
for (vector<NUM>::iterator i = v.begin(); i != v.end(); i++)
{
cout << *i << endl;
}
*/
return 0;
}
// remember to use x only LOCALLY!!!
NUM getCost(Matrix& matrix, size_t x, size_t y, vector<bool>& colUsed)
{
// pathCost
NUM pathCost = matrix.matrix[x++][y];
for (size_t col = 0; col < matrix.size(); col++)
{
if (!colUsed.at(col))
{
NUM min =
#if defined NUM_INT
INT_MAX;
#endif
#if defined NUM_DBL
DBL_MAX;
#endif
size_t row = x;
for (; row < matrix.size(); row++)
{
if (min > matrix.matrix[row][col])
{
min = matrix.matrix[row][col];
}
}
pathCost += min;
}
}
return pathCost;
}
void run(Matrix& matrix, vector<size_t>& assignedJobs)
{
// array of used columns
vector<bool> colUsed;
for (size_t i = 0; i < matrix.size(); i++)
{
colUsed.push_back(false);
}
for (size_t row = 0; row < matrix.size(); row++)
{
size_t col = 0;
// bombona
while (colUsed.at(col++)); col--;
// choose the best job for the current worker
vector<NUM> jobs;
// get all the job costs from which to choose the smallest
// row++
jobs.push_back(getCost(matrix, col, row, colUsed));
// iterator at the position of the smallest element of jobs
vector<NUM>::iterator i_min = min_element(jobs.begin(), jobs.end());
// index of the smallest element in jobs
size_t index = (size_t)distance(jobs.begin(), i_min);
colUsed.at(index) = true;
assignedJobs.push_back(index);
}
}
I know i might be out of track. I didn't use lower bound in the beginning, i'm actually a little confused how this algorithm exactly works. So even step by step walktrough through the algorithm would be helpful.

vector data not adding in while loop

I am trying to add the elements of a vector of doubles (belonging to a class called path) into a double called dist using a for loop twice. I want it to add all the distances inside the class vector for the first iteration and then at the end set the double dist back to zero and add them up again. However, when I run it, it works fine the first time as it prints out the correct answer of 3, but the double ends up being 0 by the time it prints out the second time and after the loop is done. It looks like it is not adding the vector's data. Why is this happening? Thanks for any help
class Path
{
public:
vector<double> distance;
vector<double> safety;
};
int main()
{
int i = 0;
int k = 0;
vector<Path*> paths;
Path* paths.at(0) = new Path;
Path* paths.at(1) = new Path;
paths.at(0)->distance.push_back(1.0);
paths.at(0)->distance.push_back(2.0);
paths.at(1)->distance.push_back(1.0);
paths.at(1)->distance.push_back(2.0)
double dist = 0;
for(k = 0; k < paths.size(); k++)
{
for(i = 0; i< paths.at(k)->distance.size(); i++)
{
dist += paths.at(i)->distance.at(i);
}
cout << dist << endl;
dist = 0;
}
delete paths.at(0); delete paths.at(1);
return 0;
}
This line has a bug:
dist += paths.at(i)->distance.at(i);
Should be:
dist += paths.at(k)->distance.at(i);
for(k = 0; k < route -> distance.size(); k++)
{
for(i = 0; i< route->distance.size(); i++)
{
dist += route->distance.at(i);
}
cout << dist << endl;
dist = 0;
}
This will give you k outputs (that is, it will iterator over the vector k times). If you just want to iterate over the vector twice, then this is not how you want to write your loops. Instead, you'll want 2 separate (not nested) loops:
for (int i = 0; i < route->distance.size(); ++i)
{
dist += route->distance[i];
}
cout << dist << endl;
dist = 0;
for (int k = 0; k < route->distance.size(); ++k)
{
dist += route->distance[k];
}
cout << dist << endl;
Or you could use a function that would do that for you:
dist = std::accumulate(route->distance.begin(), route->distance.end(), 0);
Edit
With your update, you now have invalid operations:
vector<Path*> paths;
Path* paths.at(0) = new Path; // at(0) does not exist! exception will be thrown
Path* paths.at(1) = new Path; // same here
It's C++, use its power:
#include <numeric>
#include <vector>
#include <iostream>
struct Path
{
std::vector<double> distance;
std::vector<double> safety;
};
int main()
{
std::vector<Path> paths{
{
{ 1.0, 2.0 }, {}
},
{
{ 3.0 }, {}
}
};
// loop version
double sum = 0.0;
for ( auto const& path : paths ) {
for ( double d : path.distance ) {
sum += d;
}
}
std::cout << sum << std::endl;
// ...
algorithm version
std::cout <<
std::accumulate(
paths.begin(),
paths.end(),
0,
[](double res, Path const& path) {
return res + std::accumulate(
path.distance.begin(),
path.distance.end(),
0);
})
<<std::endl;
}
-> Ideone
use RAII
use algorithms range-based loops if you insist on loops
don't forget software design

Algorithm to compute mode

I'm trying to devise an algorithm in the form of a function that accepts two parameters, an array and the size of the array. I want it to return the mode of the array and if there are multiple modes, return their average. My strategy was to take the array and first sort it. Then count all the occurrences of a number. while that number is occurring, add one to counter and store that count in an array m. So m is holding all the counts and another array q is holding the last value we were comparing.
For example: is my list is {1, 1, 1, 1, 2, 2, 2}
then i would have m[0] = 4 q[0] = 1
and then m[1] = 3 and q[1] = 2.
so the mode is q[0] = 1;
unfortunately i have had no success thus far. hoping someone could help.
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, k = 0, counter = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
for(int j = 0; j < n; j++){
while(y[i] == y[j]) {
counter++;
i++;
}
}
m[k] = counter;
q[k] = y[i];
i--; //i should be 1 less since it is referring to an array subscript
k++;
counter = 0;
}
}
Even though you have some good answers already, I decided to post another. I'm not sure it really adds a lot that's new, but I'm not at all sure it doesn't either. If nothing else, I'm pretty sure it uses more standard headers than any of the other answers. :-)
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <map>
#include <iostream>
#include <utility>
#include <functional>
#include <numeric>
int main() {
std::vector<int> inputs{ 1, 1, 1, 1, 2, 2, 2 };
std::unordered_map<int, size_t> counts;
for (int i : inputs)
++counts[i];
std::multimap<size_t, int, std::greater<size_t> > inv;
for (auto p : counts)
inv.insert(std::make_pair(p.second, p.first));
auto e = inv.upper_bound(inv.begin()->first);
double sum = std::accumulate(inv.begin(),
e,
0.0,
[](double a, std::pair<size_t, int> const &b) {return a + b.second; });
std::cout << sum / std::distance(inv.begin(), e);
}
Compared to #Dietmar's answer, this should be faster if you have a lot of repetition in the numbers, but his will probably be faster if the numbers are mostly unique.
Based on the comment, it seems you need to find the values which occur most often and if there are multiple values occurring the same amount of times, you need to produce the average of these. It seems, this can easily be done by std::sort() following by a traversal finding where values change and keeping a few running counts:
template <int Size>
double mode(int const (&x)[Size]) {
std::vector<int> tmp(x, x + Size);
std::sort(tmp.begin(), tmp.end());
int size(0); // size of the largest set so far
int count(0); // number of largest sets
double sum(0); // sum of largest sets
for (auto it(tmp.begin()); it != tmp.end(); ) {
auto end(std::upper_bound(it, tmp.end(), *it));
if (size == std::distance(it, end)) {
sum += *it;
++count;
}
else if (size < std::distance(it, end)) {
size = std::distance(it, end);
sum = *it;
count = 1;
}
it = end;
}
return sum / count;
}
If you simply wish to count the number of occurences then I suggest you use a std::map or std::unordered_map.
If you're mapping a counter to each distinct value then it's an easy task to count occurences using std::map as each key can only be inserted once. To list the distinct numbers in your list simply iterate over the map.
Here's an example of how you could do it:
#include <cstddef>
#include <map>
#include <algorithm>
#include <iostream>
std::map<int, int> getOccurences(const int arr[], const std::size_t len) {
std::map<int, int> m;
for (std::size_t i = 0; i != len; ++i) {
m[arr[i]]++;
}
return m;
}
int main() {
int list[7]{1, 1, 1, 1, 2, 2, 2};
auto occurences = getOccurences(list, 7);
for (auto e : occurences) {
std::cout << "Number " << e.first << " occurs ";
std::cout << e.second << " times" << std::endl;
}
auto average = std::accumulate(std::begin(list), std::end(list), 0.0) / 7;
std::cout << "Average is " << average << std::endl;
}
Output:
Number 1 occurs 4 times
Number 2 occurs 3 times
Average is 1.42857
Here's a working version of your code. m stores the values in the array and q stores their counts. At the end it runs through all the values to get the maximal count, the sum of the modes, and the number of distinct modes.
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, j = 0, k = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
j = i;
while (y[j] == y[i]) {
j++;
}
m[k] = y[i];
q[k] = j - i;
k++;
i = j;
}
int max = 0;
int modes_count = 0;
int modes_sum = 0;
for (int i=0; i < k; i++) {
if (q[i] > max) {
max = q[i];
modes_count = 1;
modes_sum = m[i];
} else if (q[i] == max) {
modes_count += 1;
modes_sum += m[i];
}
}
return modes_sum / modes_count;
}