Bidirectional Implementation of Dijkstra's Algorithm in C++ - c++

I recently just started to learn c++ and for my next homework assignment I have to implement a bidirectional version of dijkstra's algorithm. I'm supposed to build on my last assignment which makes a graph using vectors. I'm wondering what the best way to setup this assignment using my code. Here is the actual assignment:
Machine Problem 3: Bidirectional shortest path algorithm : Ira Pohl Jan 24, 2014
Objective : Improve your Graph Class and add Dijkstra and Bidirectional algorithm
Graph algorithms and graph representation is a critical tool in CS. The basic problem will be to write Dijkstra’s algorithm as a class member function (method in OO speak). You should already know Dijkstra’s algorithm for the shortest path problem from prior experience, but it will be reviewed in class. It is the basis for many route calculations and optimizations programs.
There are 2 basic implementations used for graphs – one is edge lists, and the other is connectivity matrices. You can decide which to use, but comment on your choice.
Basic problem: Write a set of constructors for declaring and initializing a graph or use your previous implementation of graph. An edge will have a positive cost that is its distance. Have a procedure that can for a graph of at least size 1000 produce a randomly generated set of edges with positive distances. Assume the graphs are undirected. The random graph procedure should have edge density as a parameter and distance range as a parameter. So a graph whose density is 0.1 would have 10% of its edges picked at random and its edge distance would be selected at random from the distance range. This of course was already developed in problem 2.
The Dijkstra bi-directional algorithm should re-use code from the Dijkstra unidirectional algorithm.
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <cmath>
double probability(){ return 1.0*rand()/RAND_MAX;}
using namespace std;
//class that has make_graph as constructor
class Graph{
public:
Graph(int s, double density);
void print_graph();
private:
int size;
vector<vector<bool> > g1; //A vector of vectors of bools
//Think of a vector as a first in, last out Data Structure
};
//make_graph altered to work in c++
Graph::Graph(int s, double density){
this->size = s;
for (int i = 0; i < s; ++i){
// We push a new vector of bool onto the initial vector s times
// The * is there to dereference the new vector that we insert
this->g1.push_back( *( new vector<bool>() ) );
for (int j = 0; j < s; ++j){
//then, on each of those vectors, we push a default "false" s times
this->g1.at(i).push_back(false);
}
}
//Don't have to change this part much
for (int i = 0; i < s; ++i){
for (int j = 0; j < s; ++j){
if (probability()< density) this->g1[i][j] = true;
}
}
}
//simple conversion, just needed 'this'
void Graph::print_graph(){
cout << "graph size " << this->size << "\n";
for(int i = 0; i < this->size; ++i){
for (int j = 0; j < this->size; ++j){
cout << this->g1[i][j] << "\t";
}
cout << "\n";
}
}
int main(){
srand(time(0));
cout << "Test simple graph generation\n";
Graph* test1 = new Graph(10, 0.7);
test1->print_graph();
cout << "\nEND of TEST 1\n\n";
Graph* test2 = new Graph(8, 0.5);
test2->print_graph();
cout << "\nEND of TEST 2\n\n";
return 0;
}

Related

Backtrack through coin collection matrix to determine the optimal path?

I've been assigned the, from what I've seen, fairly common problem when learning dynamic programming of having a nxm matrix of coins with a robot starting at the top left of the matrix [0,0] and trying to reach the bottom right of the matrix while picking up as many coins as possible. The robot is only allowed to move right and down. I have successfully been able to count the maximum number of coins that can be collected from the matrix, my code is below:
#include <iostream>
using namespace std;
int CoinCollection(int coinGrid[5][6])
{
int F[5][6] = {0};
F[0][0] = coinGrid[0][0];
for(int j = 1; j<6; j++)
{
F[0][j] = F[0][j-1]+coinGrid[0][j];
}
for(int i=1; i<5; i++)
{
F[i][0] = F[i-1][0] + coinGrid[i][0];
for(int j = 1; j<6; j++)
{
F[i][j] = max(F[i-1][j], F[i][j-1])+coinGrid[i][j];
}
}
return F[4][5];
}
string RobotPath(int coinGrid[5][6])
{
return "";
}
int main()
{
int grid[5][6] = {
{0,0,0,0,1,0},
{0,1,0,1,0,0},
{0,0,0,1,0,1},
{0,0,1,0,0,1},
{1,0,0,0,1,0} };
cout << "Max amount of coins collected is " << CoinCollection(grid);
cout << "\n\nRobot's path is" << RobotPath(grid);
}
The instructions I have say to hardcode the grid being used, so I don't have to change what I have to be flexible with inputs. The second part of the problem instructs to output the path that the robot should follow to reach the max number of coins (where the RobotPath method is). From the help I've received from my professor, I need to backtrack from the final solution to the beginning for this, but I'm at a loss for how to do this.

How to fix a directed graph on undirected?

I can not correctly correct the code so that the graph was undirected. By input, by condition, there should be a number of vertices, edges and then a list of adjacent vertices and their weight
using namespace std;
const int inf = 10000000;
struct edge {
int u, v, w;
};
int n, m, v, i;
vector<edge> e;
void solve() {
vector<int> d(n, inf);
d[v] = 0;
for (;;) {
bool any = false;
for (int j = 0; j < m; ++j)
if (d[e[j].u] < inf)
if (d[e[j].v] > d[e[j].u] + e[j].w) {
d[e[j].v] = d[e[j].u] + e[j].w;
any = true;
}
if (!any) break;
}
cout << d[d.size()-1] << endl;
}
int main() {
cin >> n >> m;
edge t;
for (i = 0; i<m; i++)
{
cin >> t.u >> t.v >> t.w;
t.u--; t.v--;
e.push_back(t);
}
solve();
}
From mathematical point of view an undirected graph should be equivalent to a directed one if you substitute every undirected edge with a pair of directed edges with opposite directions.
As far as I can see, you are trying to implement the Bellman-Ford algorithm. Some notes regarding your implementation. As I can see, your v global variable is not initialized properly. Is that intentional to assume that the source is the vertex with the index 0? Bellman-Ford finds the shortest paths from the source to all other vertices; you output the length of the path to the vertex with the maximum index, is that what you expect?
One major issue: what would happen if you have a negative cycle (that is possible, as you use signed int for storing the weights)? The benefit of the Bellman-Ford algorithm is that it works correctly if some of the graph's edges have negative weights. Moreover, it allows you to detect the presence of negative cycles, but in your case the algorithm would get into an infinite loop. The solution is to limit the number of iterations with n; if on the n-th iteration you find that you still haven't left the loop, there is an negative cycle in your graph.

Generating random Graph

Have someone input an integer N as the number of vertices in the graph.
Assign random weights on each edges ranging from 1 to 10. Not all possible edges
are present though! As in the above example, represented an absent edge by an X.
Return a pair (M,L), with M and L respectively being the matrix and list representation
of the (same) random graph you are generating.
Use non-digit characters as vertex names, to avoid confusion with edge weights.
#include <iostream>
#include <stdlib.h>
using namespace std;
void gen_random_graph(int n)
{
int adj_matrix[n][n];
for(int u = 0; u < n; u++)
{
for (int v = 0; v < n; v++)
{
if(adj_matrix[u][v]==adj_matrix[v][u])
{
adj_matrix[u][v] = rand() % 10 + 1;
cout << adj_matrix[u][v] << endl;
}
}
}
}
int main()
{
int N;
cout << "enter number of vertices" << endl;
cin >> N;
gen_random_graph(N);
return 0;
}
THis is my code so far. Is it generateing the weights ? and what does it mean i have to return a pair?
A graph can be represented as an N x N adjacency matrix (as you have already set up), where the value in matrix[i][j] corresponds to the weight of the edge connecting vertex i to vertex j. A zero corresponds to there not being a connection between i and j. If matrix[i][j] == matrix[j][i], then you have an undirected graph. Furthermore, a random graph would have random values as the edges between vertices.
In the case where every edge either exists or doesn't exist (i.e. weights are either 0 or 1), you could have the following:
This image is stolen from the internet, so I take no credit for it. Note that you can easily confirm that the first graph is undirected because the adjacency matrix is symmetric. Likewise, the second graph is directed because the matrix is NOT symmetric.

How to input an matrix style txt file instead of defining my own int 2D array for C++

So I'm pretty new to C++ but i think im gettting the hang of it a bit.
As part of an excersize, I have to take an input text file and apply this in a "shortest distance algorithm" where ultimatly I want to output all the shortest distances and routes but i haven't gotten that far yet. I have used the Floyd Warshall algorithm.
For now my question is, how do i replace a self written int array by a text input. the input array is just numbers but actually represents distances between nodes. The test array that im using now only has 3 nodes, but i want to be able to expand it to a much larger node amout, say 100.
example test matrix:
0 1234567 100
1234567 0 400
100 400 0
Should be read as:
node1 node2 node3
node 1 0 999999 100
node 2 999999 0 400
node 3 100 400 0
The large numbers: 999999 represents a distance that is too large too count as a edge.
As of now my code looks something like this:
#include<stdio.h>
// Number of vertices
#define V 3
// Define 999999 as a distance that is too large to represent a edge connection
#define TooLarge 999999
// The print function
void printSolution(int dist[][V]);
// Distance algorithm
void Distance (int distgraph[][V])
{
// output matrix that will have the shortest distance for every vertice
int dist[V][V], i, j, k;
// initial values for shortest distance are based on shortest paths.
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
dist[i][j] = distgraph[i][j];
// Add all vertices to the set of intermediate vertices.
for (k = 0; k < V; k++)
{
// use all vertices as seperate source
for (i = 0; i < V; i++)
{
// use all vertices as destination for the earlier determined source
for (j = 0; j < V; j++)
{
// If vertex k is on the shortest path from i to j, then update the value of dist[i][j]
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// Print the shortest distance matrix
printSolution(dist);
}
// The print function
void printSolution(int dist[][V])
{
printf ("Shortest distance matrix \n");
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
if (dist[i][j] == 999999)
printf("%7s", "TooLarge");
else
printf ("%7d", dist[i][j]);
}
printf("\n");
}
}
// driver program to test above function
int main()
{
int distgraph[V][V] = { {0, 1234567, 100},
{1234567, 0, 400},
{100, 400, 0,},
};
// Print the solution
Distance(distgraph);
return 0;
}
Hopefully someone can help me, I have the feeling im just forgetting something stupid. I have tried to inport the textfile using this type of code:
using namespace std;
double distances [3][3];
int main () {
int x, y;
ifstream in("citytest.txt");
if (!in) {
cout << "Cannot open file.\n";
return 0;
}
for (y = 0; y < 3; y++) {
for (x = 0; x < 3; x++) {
in >> distances[x][y];
}
}
cout << distances[3][3] << " " << endl;
in.close();
Which i know works, but only inports a predetermind part of the matrix whereas i want to input the entire array. (the cout function is just there to test if the correct distances were given as an input)
You cannot efficiently allocate the container unless you know big the workload in your external data file is.
Thus:
tokenize the first line of your file and take the dimension N from that
allocate your container accordingly
then consume the rest of the file and put the data into the container; maybe throw if a row's length doesn't match N, or if there are not N rows.
You may consider that
representing a graph by a full adjacency matrix is a debatable concept; it's space-inefficient and time-inefficient for sparse graphs
a 2D c-array is not the only possible representation of a matrix; you may consider a flat std container and implement a slice-style access on it
last not least you may want to have a look at boost::graph

Sampling Data into two Groups

I am seeking help to make the code below efficient. I not satisfied though it works. There is bug to be fixed (currently irrelevant). I am using < random> header for the first time and stable_partition for first time.
The Problem definition/specification:
I have a population (vector) of numerical data (float values). I want to create two RANDOM samples (2 vectors) based on a user specified percentage. i.e. popu_data = 30%Sample1 + 70%Sample2 - here 30% will be given by the user. I didnt implement as % yet but its trivial.
The Problem in Programming: I am able to create the 30% Sample from the population. The 2nd part of creating another vector (sample2 - 70%) is my problem. The reason being while selecting the 30% data, I have to select the values randomly. I have to keep track of the indexes to remove them. But some how I am not getting an efficient logic than the one I implemented.
My Logic is (NOT happy): In the population data, the values at random indexes are replaced with a unique value (here it is 0.5555). Later I learnt about stable_partition function where individual values of the Population are compared with 0.5555. On false, that data is created as a new Sample2 which complements sample1.
Further to this: How can I make this Generic i.e. a population into N sub-samples of user defined % of population.
Thank you for any help. I tried vector erase, remove, copy etc but it didn't materialize as the current code. I am looking for a better and more efficient logic and stl usage.
#include <random>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Is05555 (float i){
if ( i > 0.5560 ) return true;
return false;
}
int main()
{
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<> dis(1, 2);
vector<float>randVals;
cout<<"All the Random Values between 1 and 2"<<endl;
for (int n = 0; n < 20; ++n) {
float rnv = dis(gen);
cout<<rnv<<endl;
randVals.push_back(rnv);
}
cout << '\n';
random_device rd2;
mt19937 gen2(rd2());
uniform_int_distribution<int> dist(0,19);
vector<float>sample;
vector<float>sample2;
for (int n = 0; n < 6; ++n) {
float rnv = dist(gen2);
sample.push_back(randVals.at(rnv));
randVals.at(rnv) = 0.5555;
}
cout<<"Random Values between 1 and 2 with 0.5555 a Unique VAlue"<<endl;
for (int n = 0; n < 20; ++n) {
cout<<randVals.at(n)<<" ";
}
cout << '\n';
std::vector<float>::iterator bound;
bound = std::stable_partition (randVals.begin(), randVals.end(), Is05555);
for (std::vector<float>::iterator it=randVals.begin(); it!=bound; ++it)
sample2.push_back(*it);
cout<<sample.size()<<","<<sample2.size()<<endl;
cout<<"Random Values between 1 and 2 Subset of 6 only: "<<endl;
for (int n = 0; n < sample.size(); ++n) {
cout<<sample.at(n)<<" ";
}
cout << '\n';
cout<<"Random Values between 1 and 2 - Remaining: "<<endl;
for (int n = 0; n < sample2.size(); ++n) {
cout<<sample2.at(n)<<" ";
}
cout << '\n';
return 0;
}
Given a requirement for an N% sample, with order irrelevant, it's probably easiest to just do something like:
std::random_shuffle(randVals.begin(), randVals.end());
int num = randVals.size() * percent / 100.0;
auto pos = randVals.begin() + randVals.size() - num;
// get our sample
auto sample1{pos, randVals.end()};
// remove sample from original collection
randVals.erase(pos, randVals.end());
For some types of items in the array, you could improve this by moving items from the original array to the sample array, but for simple types like float or double, that won't accomplish anything.