Skip to content

Commit 3662548

Browse files
authored
Merge pull request #57 from Debashis08/feature-graph-implementation
Feature graph implementation
2 parents 84a5c35 + efe64c2 commit 3662548

File tree

5 files changed

+234
-0
lines changed

5 files changed

+234
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include<map>
4+
#include<vector>
5+
using namespace std;
6+
7+
namespace MaximumFlowFordFulkerson
8+
{
9+
class Graph
10+
{
11+
private:
12+
int _noOfVertices;
13+
int _source;
14+
int _sink;
15+
int _maximumFlow;
16+
bool _flagParallelEdges;
17+
vector<vector<int>> _adjMatrix;
18+
vector<vector<int>> _residualGraph;
19+
vector<int> _parent;
20+
vector<bool> _visited;
21+
void ResolveAntiParallelEdges();
22+
void DepthFirstSearchVisit(int nodeU);
23+
bool DepthFirstSearch();
24+
public:
25+
void CreateGraph(int noOfVertices);
26+
void PushDirectedEdge(int valueU, int valueV, int capacity);
27+
int FindMaximumFlowFordFulkerson();
28+
};
29+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include "../Headers/0003_Graph/0015_MaximumFlowFordFulkerson.h"
2+
#include<climits>
3+
using namespace std;
4+
5+
namespace MaximumFlowFordFulkerson
6+
{
7+
// Graph Private Member Methods
8+
void Graph::ResolveAntiParallelEdges()
9+
{
10+
int countParallelEdges = 0;
11+
for (int i = 0; i < this->_noOfVertices; i++)
12+
{
13+
for (int j = 0; j < this->_noOfVertices; j++)
14+
{
15+
if (this->_adjMatrix[i][j] > 0 && this->_adjMatrix[j][i] > 0)
16+
{
17+
countParallelEdges++;
18+
}
19+
}
20+
}
21+
22+
// As i->j and j->i both edges has been counted, actual count is count = count / 2
23+
countParallelEdges /= 2;
24+
25+
this->_flagParallelEdges = countParallelEdges > 0;
26+
27+
// If there are no anti-parallel edges, no need to modify the adjMatrix
28+
if (!this->_flagParallelEdges)
29+
{
30+
return;
31+
}
32+
33+
int newNoOfVertices = this->_noOfVertices + countParallelEdges;
34+
35+
// Modifying the adjMatrix
36+
for (auto& edge : this->_adjMatrix)
37+
{
38+
edge.resize(newNoOfVertices, 0);
39+
}
40+
int k = this->_noOfVertices;
41+
this->_visited.resize(newNoOfVertices, false);
42+
this->_parent.resize(newNoOfVertices, -1);
43+
this->_adjMatrix.resize(newNoOfVertices, vector<int>(newNoOfVertices, 0));
44+
45+
// Removing the anti-parallel edges by adding new nodes
46+
for (int i = 0; i < this->_noOfVertices; i++)
47+
{
48+
for (int j = 0; j < this->_noOfVertices; j++)
49+
{
50+
if (this->_adjMatrix[i][j] > 0 && this->_adjMatrix[j][i] > 0)
51+
{
52+
this->_adjMatrix[i][k] = this->_adjMatrix[i][j];
53+
this->_adjMatrix[k][j] = this->_adjMatrix[i][j];
54+
this->_adjMatrix[i][j] = 0;
55+
k++;
56+
}
57+
}
58+
}
59+
60+
// Updating the total no of vertices after modifying the adjMatrix
61+
this->_noOfVertices = newNoOfVertices;
62+
}
63+
64+
void Graph::DepthFirstSearchVisit(int nodeU)
65+
{
66+
this->_visited[nodeU] = true;
67+
for (int nodeV = 0; nodeV < this->_noOfVertices; nodeV++)
68+
{
69+
if (!this->_visited[nodeV] && this->_residualGraph[nodeU][nodeV] > 0)
70+
{
71+
this->_parent[nodeV] = nodeU;
72+
this->DepthFirstSearchVisit(nodeV);
73+
}
74+
}
75+
}
76+
77+
bool Graph::DepthFirstSearch()
78+
{
79+
// Resetting the visited values
80+
fill(this->_visited.begin(), this->_visited.end(), false);
81+
82+
// Resetting the parent values
83+
fill(this->_parent.begin(), this->_parent.end(), -1);
84+
85+
// Starting the DepthFirstSearch from the source vertex
86+
this->DepthFirstSearchVisit(this->_source);
87+
88+
// Returning the visited value of the sink vertex, initially it was set to false
89+
return this->_visited[this->_sink];
90+
}
91+
92+
// Graph Public Member Methods
93+
void Graph::CreateGraph(int noOfVertices)
94+
{
95+
this->_noOfVertices = noOfVertices;
96+
this->_source = 0;
97+
this->_sink = this->_noOfVertices - 1;
98+
this->_maximumFlow = 0;
99+
this->_flagParallelEdges = false;
100+
this->_adjMatrix = vector<vector<int>>(this->_noOfVertices, vector<int>(this->_noOfVertices, 0));
101+
this->_parent = vector<int>(this->_noOfVertices, -1);
102+
this->_visited = vector<bool>(this->_noOfVertices, false);
103+
}
104+
105+
void Graph::PushDirectedEdge(int valueU, int valueV, int capacity)
106+
{
107+
this->_adjMatrix[valueU][valueV] = capacity;
108+
}
109+
110+
int Graph::FindMaximumFlowFordFulkerson()
111+
{
112+
// Resolving all the parallel edges if present
113+
this->ResolveAntiParallelEdges();
114+
this->_residualGraph = this->_adjMatrix;
115+
116+
// While there exists a path p from source to sink in the residual network G'
117+
while (this->DepthFirstSearch())
118+
{
119+
int augmentedPathFlow = INT_MAX;
120+
121+
// Calculating c'(p) = min{ c'(u,v) : (u,v) is in p }
122+
for (int nodeV = this->_sink; nodeV > this->_source; nodeV = this->_parent[nodeV])
123+
{
124+
int nodeU = this->_parent[nodeV];
125+
augmentedPathFlow = min(augmentedPathFlow, this->_residualGraph[nodeU][nodeV]);
126+
}
127+
128+
for (int nodeV = this->_sink; nodeV > this->_source; nodeV = this->_parent[nodeV])
129+
{
130+
int nodeU = this->_parent[nodeV];
131+
this->_residualGraph[nodeU][nodeV] -= augmentedPathFlow;
132+
this->_residualGraph[nodeV][nodeU] += augmentedPathFlow;
133+
}
134+
this->_maximumFlow += augmentedPathFlow;
135+
}
136+
137+
return this->_maximumFlow;
138+
}
139+
}

SourceCodes/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ set(0003GRAPH_SOURCES
1414
0012_DifferenceConstraintsShortestPaths.cc
1515
0013_AllPairsShortestPathsFloydWarshall.cc
1616
0014_AllPairsShortestPathsJohnson.cc
17+
0015_MaximumFlowFordFulkerson.cc
1718

1819
)
1920

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include<gtest/gtest.h>
2+
#include "../Headers/0003_Graph/0015_MaximumFlowFordFulkerson.h"
3+
#include "../0000_CommonUtilities/UnitTestHelper.h"
4+
5+
namespace MaximumFlowFordFulkerson
6+
{
7+
UnitTestHelper unitTestHelper;
8+
9+
TEST(MaximumFlowFordFulkerson, GraphWithNoParallelEdges)
10+
{
11+
// Arrange
12+
Graph graph;
13+
int noOfVertices = 6;
14+
int expectedMaximumFlow = 23;
15+
16+
17+
// Act
18+
graph.CreateGraph(noOfVertices);
19+
20+
graph.PushDirectedEdge(0, 1, 16);
21+
graph.PushDirectedEdge(0, 2, 13);
22+
graph.PushDirectedEdge(1, 3, 12);
23+
graph.PushDirectedEdge(2, 1, 4);
24+
graph.PushDirectedEdge(2, 4, 14);
25+
graph.PushDirectedEdge(3, 2, 9);
26+
graph.PushDirectedEdge(3, 5, 20);
27+
graph.PushDirectedEdge(4, 3, 7);
28+
graph.PushDirectedEdge(4, 5, 4);
29+
30+
int actualMaximumFlow = graph.FindMaximumFlowFordFulkerson();
31+
32+
// Assert
33+
ASSERT_EQ(expectedMaximumFlow, actualMaximumFlow);
34+
}
35+
36+
TEST(MaximumFlowFordFulkerson, GraphWithParallelEdges)
37+
{
38+
// Arrange
39+
Graph graph;
40+
int noOfVertices = 6;
41+
int expectedMaximumFlow = 24;
42+
43+
44+
// Act
45+
graph.CreateGraph(noOfVertices);
46+
47+
graph.PushDirectedEdge(0, 1, 16);
48+
graph.PushDirectedEdge(0, 2, 13);
49+
graph.PushDirectedEdge(1, 3, 12);
50+
graph.PushDirectedEdge(1, 2, 6);
51+
graph.PushDirectedEdge(2, 1, 10);
52+
graph.PushDirectedEdge(2, 4, 14);
53+
graph.PushDirectedEdge(2, 3, 2);
54+
graph.PushDirectedEdge(3, 2, 11);
55+
graph.PushDirectedEdge(3, 5, 20);
56+
graph.PushDirectedEdge(4, 3, 7);
57+
graph.PushDirectedEdge(4, 5, 4);
58+
59+
int actualMaximumFlow = graph.FindMaximumFlowFordFulkerson();
60+
61+
// Assert
62+
ASSERT_EQ(expectedMaximumFlow, actualMaximumFlow);
63+
}
64+
}

Tests/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_executable(
2626
0012_DifferenceConstraintsShortestPathsTest.cc
2727
0013_AllPairsShortestPathsFloydWarshallTest.cc
2828
0014_AllPairsShortestPathsJohnsonTest.cc
29+
0015_MaximumFlowFordFulkersonTest.cc
2930
)
3031

3132
target_link_libraries(

0 commit comments

Comments
 (0)