diff --git a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h new file mode 100644 index 0000000..683dfa2 --- /dev/null +++ b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + class Node + { + public: + string data; + int distance; + Node(string data); + }; + + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class Graph + { + private: + map> _adjlist; + map _nodeMap; + vector _edgeList; + Node* MakeOrFindNode(string data); + void PushDirectedEdge(string valueU, string valueV, int weight); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + + public: + void PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB); + bool FindDifferenceConstraintsSolutionBellmanFord(); + vector> GetDifferenceConstrtaintsSolution(); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc new file mode 100644 index 0000000..20b7784 --- /dev/null +++ b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc @@ -0,0 +1,133 @@ +#include"../Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h" +#include +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + Node::Node(string data) + { + this->data = data; + this->distance = INT_MAX; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(string data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph::PushDirectedEdge(string dataU, string dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeList.push_back(new Edge(nodeU, nodeV, weight)); + } + + void Graph::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + } + sourceNode->distance = 0; + } + + void Graph::Relax(Edge* edge) + { + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) + { + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + } + } + + // Graph Public Member Methods + void Graph::PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB) + { + // Creating the Actual Graph + string valueU = ""; + string valueV = ""; + int weight = 0; + for (int i = 0; i < vectorA.size(); i++) + { + for (int j = 0; j < vectorX.size(); j++) + { + if (vectorA[i][j] == 1) + { + valueV= vectorX[j]; + } + if (vectorA[i][j] == -1) + { + valueU = vectorX[j]; + } + } + weight = vectorB[i]; + this->PushDirectedEdge(valueU, valueV, weight); + } + + // Creating all the edges from the additional vertex + valueU = ""; + valueV = ""; + weight = 0; + for (int i = 0; i < vectorX.size(); i++) + { + valueV = vectorX[i]; + this->PushDirectedEdge(valueU, valueV, weight); + } + } + + bool Graph::FindDifferenceConstraintsSolutionBellmanFord() + { + Node* source = this->_nodeMap[""]; + + this->InitializeSingleSource(source); + + for (int i = 0; i < this->_nodeMap.size(); i++) + { + for (auto& edge : this->_edgeList) + { + this->Relax(edge); + } + } + + for (auto& edge : this->_edgeList) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + return false; + } + } + return true; + } + + vector> Graph::GetDifferenceConstrtaintsSolution() + { + vector> result; + for (auto& node : this->_nodeMap) + { + if (node.second->data != "") + { + result.push_back({ node.second->data, node.second->distance }); + } + } + return result; + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index eb010e7..d2171df 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -11,6 +11,7 @@ set(0003GRAPH_SOURCES 0009_SingleSourceShortestPathBellmanFord.cc 0010_DirectedAcyclicGraphShortestPath.cc 0011_SingleSourceShortestPathDijkstra.cc + 0012_DifferenceConstraintsShortestPaths.cc ) diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index c903d36..6e3509e 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -73,7 +73,6 @@ class UnitTestHelper return result; } - // This helper method is used to sort the vector of vectors of a particular typename. // Each inner vector is sorted first. // Then each of them are sorted by their first element, in increasing order. @@ -109,7 +108,7 @@ class UnitTestHelper } template - bool NormalizeCyclesAnCompare(vector data1, vector data2) + bool NormalizeCyclesAndCompare(vector data1, vector data2) { if (data1.size() != data2.size()) { @@ -158,4 +157,27 @@ class UnitTestHelper }); return data; } + + template + string SortVectorOfPairAndSerialize(vector> data) + { + // Sorting the vector in non-decreasing order on typename T1 + sort(data.begin(), data.end(), [](const pair& pair1, const pair& pair2) + { + return pair1.first < pair2.first; + }); + + // Serializing the vector to string + string result = ""; + for (auto& iterator : data) + { + result += iterator.first + "(" + to_string(iterator.second) + ")" + " "; + } + + if (!result.empty()) + { + result.pop_back(); + } + return result; + } }; \ No newline at end of file diff --git a/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc index 386825d..d46a651 100644 --- a/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc +++ b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc @@ -28,6 +28,6 @@ namespace HamiltonianPathAndCycle ASSERT_TRUE(isHamiltonianCyclePresent); ASSERT_TRUE(isHamiltonianPathPresent); - ASSERT_TRUE(unitTestHelper.NormalizeCyclesAnCompare(hamiltonianPathActualResult, hamiltonianPathExpectedResult)); + ASSERT_TRUE(unitTestHelper.NormalizeCyclesAndCompare(hamiltonianPathActualResult, hamiltonianPathExpectedResult)); } } \ No newline at end of file diff --git a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc new file mode 100644 index 0000000..04b293e --- /dev/null +++ b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc @@ -0,0 +1,40 @@ +#include +#include"../Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h" +#include"../0000_CommonUtilities/UnitTestHelper.h" +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + UnitTestHelper unitTestHelper; + + TEST(DifferenceConstraints, SimpleGraph) + { + Graph graph; + + vector> vectorA = + { + {1, -1, 0, 0, 0}, + {1, 0, 0, 0, -1}, + {0, 1, 0, 0, -1}, + {-1, 0, 1, 0, 0}, + {-1, 0, 0, 1, 0}, + {0, 0, -1, 1, 0}, + {0, 0, -1, 0, 1}, + {0, 0, 0, -1, 1}, + }; + vector vectorX = { "v1", "v2", "v3", "v4", "v5" }; + vector vectorB = {0, -1, 1, 5, 4, -1, -3, -3}; + vector> expectedSolution = + { + {"v2", -3}, + {"v5", -4}, + {"v1", -5}, + {"v4", -1}, + {"v3", 0}, + }; + graph.PushAllDirectedEdges(vectorA, vectorX, vectorB); + + ASSERT_TRUE(graph.FindDifferenceConstraintsSolutionBellmanFord()); + ASSERT_EQ(unitTestHelper.SortVectorOfPairAndSerialize(graph.GetDifferenceConstrtaintsSolution()), unitTestHelper.SortVectorOfPairAndSerialize(expectedSolution)); + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 42d15cb..1d024f1 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable( 0009_SingleSourceShortestPathBellmanFordTest.cc 0010_DirectedAcyclicGraphShortestPathTest.cc 0011_SingleSourceShortestPathDijkstraTest.cc + 0012_DifferenceConstraintsShortestPathsTest.cc ) target_link_libraries(