Shortest Path
#include "ShortestPath.h"
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <math.h>
#include <random>
#include <string>
#include <vector>
// The digits of the distance value;
const unsigned int DIGITS = 1;
void
PrintGraph(const std::vector< std::vector<int> >& aGraph)
{
assert(!aGraph.empty());
unsigned int w = DIGITS + 2;
for (auto& nodes: aGraph) {
for (auto& node: nodes) {
std::cout << std::setw(w) <<
((node == INF) ? "*" : std::to_string(node)) << " ";
}
std::cout << std::endl;
}
}
// std::vector< std::vector<const int> >
std::vector< std::vector<int> >
GenerateGraph(unsigned int aSize, float aDensity, bool aDirected = true)
{
assert(aSize);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0, 1);
const unsigned int times = pow(10.0, DIGITS);
std::vector< std::vector<int> > graph;
graph.resize(aSize);
for (unsigned int i = 0 ; i < aSize ; ++i) {
graph[i].resize(aSize);
for (unsigned int j = i ; j < aSize ; ++j) {
graph[i][j] = (i == j) ? 0 : (dis(gen) < aDensity) ? dis(gen) * times : INF;
}
}
for (unsigned int i = 1 ; i < aSize ; ++i) {
for (unsigned int j = 0 ; j < i ; ++j) {
graph[i][j] = (aDirected) ? (dis(gen) < aDensity) ? dis(gen) * times : INF :
graph[j][i];
}
}
if (!aDirected) {
for (unsigned int i = 0 ; i < aSize ; ++i) {
for (unsigned int j = 0 ; j < aSize ; ++j) {
assert(graph[i][j] == graph[j][i]);
}
}
}
return graph;
}
int main()
{
// std::vector< std::vector<int> > graph = {
// { 0, 1, 12, INF, INF, INF },
// { INF, 0, 9, 3, INF, INF },
// { INF, INF, 0, INF, 5, INF },
// { INF, INF, 4, 0, 13, 15 },
// { INF, INF, INF, INF, 0, 4 },
// { INF, INF, INF, INF, INF, 0 }
// };
// std::vector< std::vector<int> > graph = GenerateGraph(6, 0.5f, false);
std::vector< std::vector<int> > graph = GenerateGraph(6, 0.3f);
std::cout << "Graph: " << std::endl;
PrintGraph(graph);
std::cout << std::endl;
std::cout << "Shortest path by Floyd-Warshall: " << std::endl;
std::vector< std::vector<int> > fw = FloydWarshall(graph);
PrintGraph(fw);
std::cout << std::endl;
std::cout << "Shortest path by Dijkstra: " << std::endl;
std::vector< std::vector<int> > dij = Dijkstra(graph);
PrintGraph(dij);
std::cout << std::endl;
std::cout << "Shortest path by Bellman-Ford-Moore: " << std::endl;
std::vector< std::vector<int> > bfm = BellmanFordMoore(graph);
PrintGraph(bfm);
assert(bfm == dij && dij == fw);
return 0;
}
CXX=g++
CFLAGS=-Wall -std=c++14
SOURCES=test.cpp\
BellmanFordMoore.cpp\
Dijkstra.cpp\
FloydWarshall.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=run_test
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) $(CFLAGS) $(OBJECTS) -o $(EXECUTABLE)
.cpp.o:
$(CXX) -c $(CFLAGS) $< -o $@
clean:
rm $(EXECUTABLE) *.o
#if !defined(SHORTEST_PATH_H)
#define SHORTEST_PATH_H
#include <vector>
const int INF = ((unsigned int) ~0) >> 1; // The max value of int.
// Graph:
// To
// +---+---+---+---+- -+---+
// | | 0 | 1 | 2 | ... | N |
// +---+---+---+---+- -+---+
// F | 0 | 0 | . | . | ... | . |
// r +---+---+---+---+- -+---+
// o | 1 | . | 0 | . | ... | . |
// m +---+---+---+---+- -+---+
// | 2 | . | . | 0 | ... | . |
// +---+---+---+---+- -+---+
// | . | ............. | . |
// . ............. .
// | . | ............. | . |
// +---+- -+---+
// | N | ............. | 0 |
// +---+- -+---+
std::vector< std::vector<int> >
Dijkstra(std::vector< std::vector<int> >& aGraph);
std::vector< std::vector<int> >
FloydWarshall(std::vector< std::vector<int> >& aGraph);
std::vector< std::vector<int> >
BellmanFordMoore(std::vector< std::vector<int> >& aGraph);
#endif // SHORTEST_PATH_H
#include "ShortestPath.h"
#include <assert.h>
std::vector< std::vector<int> >
FloydWarshall(std::vector< std::vector<int> >& aGraph)
{
assert(!aGraph.empty());
// Copy the graph so we don't change the input one.
std::vector< std::vector<int> > result = aGraph;
for (unsigned int k = 0 ; k < aGraph.size() ; ++k) {
for (unsigned int i = 0 ; i < aGraph.size() ; ++i) {
for (unsigned int j = 0 ; j < aGraph.size() ; ++j) {
if (result[i][k] >= INF || result[k][j] >= INF) {
continue;
}
int pathViaK = result[i][k] + result[k][j];
assert(pathViaK >= result[i][k] && pathViaK >= result[k][j]);
if (pathViaK < result[i][j]) {
result[i][j] = pathViaK;
}
}
}
}
return result;
}
#include "ShortestPath.h"
#include <assert.h>
unsigned int
IndexOfMin(std::vector<unsigned int>& aNodes, std::vector<int>& aDistances)
{
assert(!(aNodes.empty() || aDistances.empty()));
unsigned int index = 0;
for (unsigned int i = 1 ; i < aNodes.size() ; ++i) {
unsigned int node = aNodes[i];
if (aDistances[node] < aDistances[aNodes[index]]) {
index = i;
}
}
return index;
}
std::vector<int>
Dijkstra(std::vector< std::vector<int> >& aGraph, unsigned int aStart)
{
assert(!aGraph.empty());
// To record the shortest distance from start node to other nodes.
std::vector<int> distances(aGraph.size(), INF);
distances[aStart] = 0;
// start node
// v
// +---+---+---+- -+---+- -+---+
// node | 0 | 1 | 2 | ... | k | ... | N |
// +---+---+---+- -+---+- -+---+
// distance | * | * | * | ... | 0 | ... | * |
// +---+---+---+- -+---+- -+---+
// A set that contains the unvisited nodes from start node.
std::vector<unsigned int> unvisit;
for (unsigned int i = 0 ; i < aGraph.size() ; ++i) {
unvisit.push_back(i); // Put all nodes at the first.
}
// start node
// v
// +---+---+---+- -+---+- -+---+
// index | 0 | 1 | 2 | ... | k | ... | N |
// +---+---+---+- -+---+- -+---+
// node | 0 | 1 | 2 | ... | k | ... | N |
// +---+---+---+- -+---+- -+---+
while (!unvisit.empty()) {
// Find the nearest unvisited node from the start node.
unsigned int minIndex = IndexOfMin(unvisit, distances);
unsigned int nearest = unvisit[minIndex];
// Go to the nearest unvisited node and calculate the distances
// of all the available path via the chosen node.
unvisit.erase(unvisit.begin() + minIndex);
for (unsigned int i = 0 ; i < aGraph.size() ; ++i) {
// Skip the unconnected node.
if (distances[nearest] >= INF || aGraph[nearest][i] >= INF) {
continue;
}
// If the path via nearest is shorter than the record from start node to
// others, than we update the records.
int pathViaNearest = distances[nearest] + aGraph[nearest][i];
assert(pathViaNearest >= distances[nearest] &&
pathViaNearest >= aGraph[nearest][i]);
if (pathViaNearest < distances[i]) {
distances[i] = pathViaNearest;
}
}
}
return distances;
}
std::vector< std::vector<int> >
Dijkstra(std::vector< std::vector<int> >& aGraph)
{
std::vector< std::vector<int> > results;
results.resize(aGraph.size());
// Set the start point to calculate the shortest path.
for (unsigned int start = 0 ; start < aGraph.size() ; ++start) {
// Append the distance path from "start" to the result.
results[start] = Dijkstra(aGraph, start);
}
return results;
}
#include "ShortestPath.h"
#include <assert.h>
std::vector<int>
BellmanFordMoore(std::vector< std::vector<int> >& aGraph, unsigned int aStart)
{
assert(!aGraph.empty());
// To record the shortest distance from start node to other nodes.
std::vector<int> distances(aGraph.size(), INF);
distances[aStart] = 0;
// start node
// v
// +---+---+---+- -+---+- -+---+
// node | 0 | 1 | 2 | ... | k | ... | N |
// +---+---+---+- -+---+- -+---+
// distance | * | * | * | ... | 0 | ... | * |
// +---+---+---+- -+---+- -+---+
// <-- N - 1 edges -->
// 1 -- 2 -- 3 -- ... -- N
//
// If we have N nodes, then there are at the most (N - 1) edges
// to connect these nodes. Thus, we need to update the distances among nodes
// (N-1) times at the most.
for (unsigned int i = 0 ; i < aGraph.size() - 1 ; ++i) {
// Go throug all the edges to update the distance.
for (unsigned int j = 0 ; j < aGraph.size() ; ++j) {
for (unsigned int k = 0 ; k < aGraph.size() ; ++k) {
// Skip the unconnected node.
if (distances[j] >= INF || aGraph[j][k] >= INF) {
continue;
}
int pathToKViaJ = distances[j] + aGraph[j][k];
assert(pathToKViaJ >= distances[j] && pathToKViaJ >= aGraph[j][k]);
if (pathToKViaJ < distances[k]) {
distances[k] = pathToKViaJ;
}
}
}
}
return distances;
}
std::vector< std::vector<int> >
BellmanFordMoore(std::vector< std::vector<int> >& aGraph)
{
std::vector< std::vector<int> > results;
results.resize(aGraph.size());
// Set the start point to calculate the shortest path.
for (unsigned int start = 0 ; start < aGraph.size() ; ++start) {
// Append the distance path from "start" to the result.
results[start] = BellmanFordMoore(aGraph, start);
}
return results;
}