Skip to content

Commit fbbe243

Browse files
authored
Merge pull request #59 from Debashis08/release
Release
2 parents 9415555 + 21c277d commit fbbe243

10 files changed

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

SourceCodes/0003_Graph/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ set(0003GRAPH_SOURCES
1414
0012_DifferenceConstraintsShortestPaths.cc
1515
0013_AllPairsShortestPathsFloydWarshall.cc
1616
0014_AllPairsShortestPathsJohnson.cc
17+
0015_MaximumFlowFordFulkerson.cc
18+
0016_MaximumFlowEdmondsKarp.cc
1719

1820
)
1921

Tests/0001_Basics/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ target_link_libraries(
2626

2727

2828
include(GoogleTest)
29-
gtest_discover_tests(0001-Basics-Tests)
29+
gtest_discover_tests(0001-Basics-Tests DISCOVERY_TIMEOUT 30)

Tests/0002_Tree/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ target_link_libraries(
2121
)
2222

2323
include(GoogleTest)
24-
gtest_discover_tests(0002TreeTests)
24+
gtest_discover_tests(0002TreeTests DISCOVERY_TIMEOUT 30)

0 commit comments

Comments
 (0)