chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Has been cancelled
Awesome CI Workflow / Compile checks (macOS-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (windows-latest) (push) Has been cancelled
Awesome CI Workflow / Code Formatter (push) Has been cancelled
Awesome CI Workflow / Compile checks (macOS-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (windows-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
#If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
#with full pathname.RELATIVE may makes it easier to extract an executable name
|
||||
#automatically.
|
||||
file(GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
|
||||
#file(GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/graph")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Bidirectional Dijkstra Shortest Path Algorithm]
|
||||
* (https://www.coursera.org/learn/algorithms-on-graphs/lecture/7ml18/bidirectional-dijkstra)
|
||||
*
|
||||
* @author [Marinovksy](http://github.com/Marinovsky)
|
||||
*
|
||||
* @details
|
||||
* This is basically the same Dijkstra Algorithm but faster because it goes from
|
||||
* the source to the target and from target to the source and stops when
|
||||
* finding a vertex visited already by the direct search or the reverse one.
|
||||
* Here some simulations of it:
|
||||
* https://www.youtube.com/watch?v=DINCL5cd_w0&t=24s
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
#include <limits> /// for variable INF
|
||||
#include <queue> /// for the priority_queue of distances
|
||||
#include <utility> /// for make_pair function
|
||||
#include <vector> /// for store the graph, the distances, and the path
|
||||
|
||||
constexpr int64_t INF = std::numeric_limits<int64_t>::max();
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph Algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @namespace bidirectional_dijkstra
|
||||
* @brief Functions for [Bidirectional Dijkstra Shortest Path]
|
||||
* (https://www.coursera.org/learn/algorithms-on-graphs/lecture/7ml18/bidirectional-dijkstra)
|
||||
* algorithm
|
||||
*/
|
||||
namespace bidirectional_dijkstra {
|
||||
/**
|
||||
* @brief Function that add edge between two nodes or vertices of graph
|
||||
*
|
||||
* @param adj1 adjacency list for the direct search
|
||||
* @param adj2 adjacency list for the reverse search
|
||||
* @param u any node or vertex of graph
|
||||
* @param v any node or vertex of graph
|
||||
*/
|
||||
void addEdge(std::vector<std::vector<std::pair<uint64_t, uint64_t>>> *adj1,
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> *adj2,
|
||||
uint64_t u, uint64_t v, uint64_t w) {
|
||||
(*adj1)[u - 1].push_back(std::make_pair(v - 1, w));
|
||||
(*adj2)[v - 1].push_back(std::make_pair(u - 1, w));
|
||||
// (*adj)[v - 1].push_back(std::make_pair(u - 1, w));
|
||||
}
|
||||
/**
|
||||
* @brief This function returns the shortest distance from the source
|
||||
* to the target if there is path between vertices 's' and 't'.
|
||||
*
|
||||
* @param workset_ vertices visited in the search
|
||||
* @param distance_ vector of distances from the source to the target and
|
||||
* from the target to the source
|
||||
*
|
||||
*/
|
||||
uint64_t Shortest_Path_Distance(
|
||||
const std::vector<uint64_t> &workset_,
|
||||
const std::vector<std::vector<uint64_t>> &distance_) {
|
||||
int64_t distance = INF;
|
||||
for (uint64_t i : workset_) {
|
||||
if (distance_[0][i] + distance_[1][i] < distance) {
|
||||
distance = distance_[0][i] + distance_[1][i];
|
||||
}
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function runs the dijkstra algorithm for some source vertex and
|
||||
* target vertex in the graph and returns the shortest distance of target
|
||||
* from the source.
|
||||
*
|
||||
* @param adj1 input graph
|
||||
* @param adj2 input graph reversed
|
||||
* @param s source vertex
|
||||
* @param t target vertex
|
||||
*
|
||||
* @return shortest distance if target is reachable from source else -1 in
|
||||
* case if target is not reachable from source.
|
||||
*/
|
||||
int Bidijkstra(std::vector<std::vector<std::pair<uint64_t, uint64_t>>> *adj1,
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> *adj2,
|
||||
uint64_t s, uint64_t t) {
|
||||
/// n denotes the number of vertices in graph
|
||||
uint64_t n = adj1->size();
|
||||
|
||||
/// setting all the distances initially to INF
|
||||
std::vector<std::vector<uint64_t>> dist(2, std::vector<uint64_t>(n, INF));
|
||||
|
||||
/// creating a a vector of min heap using priority queue
|
||||
/// pq[0] contains the min heap for the direct search
|
||||
/// pq[1] contains the min heap for the reverse search
|
||||
|
||||
/// first element of pair contains the distance
|
||||
/// second element of pair contains the vertex
|
||||
std::vector<
|
||||
std::priority_queue<std::pair<uint64_t, uint64_t>,
|
||||
std::vector<std::pair<uint64_t, uint64_t>>,
|
||||
std::greater<std::pair<uint64_t, uint64_t>>>>
|
||||
pq(2);
|
||||
/// vector for store the nodes or vertices in the shortest path
|
||||
std::vector<uint64_t> workset(n);
|
||||
/// vector for store the nodes or vertices visited
|
||||
std::vector<bool> visited(n);
|
||||
|
||||
/// pushing the source vertex 's' with 0 distance in pq[0] min heap
|
||||
pq[0].push(std::make_pair(0, s));
|
||||
|
||||
/// marking the distance of source as 0
|
||||
dist[0][s] = 0;
|
||||
|
||||
/// pushing the target vertex 't' with 0 distance in pq[1] min heap
|
||||
pq[1].push(std::make_pair(0, t));
|
||||
|
||||
/// marking the distance of target as 0
|
||||
dist[1][t] = 0;
|
||||
|
||||
while (true) {
|
||||
/// direct search
|
||||
|
||||
// If pq[0].size() is equal to zero then the node/ vertex is not
|
||||
// reachable from s
|
||||
if (pq[0].size() == 0) {
|
||||
break;
|
||||
}
|
||||
/// second element of pair denotes the node / vertex
|
||||
uint64_t currentNode = pq[0].top().second;
|
||||
|
||||
/// first element of pair denotes the distance
|
||||
uint64_t currentDist = pq[0].top().first;
|
||||
|
||||
pq[0].pop();
|
||||
|
||||
/// for all the reachable vertex from the currently exploring vertex
|
||||
/// we will try to minimize the distance
|
||||
for (std::pair<int, int> edge : (*adj1)[currentNode]) {
|
||||
/// minimizing distances
|
||||
if (currentDist + edge.second < dist[0][edge.first]) {
|
||||
dist[0][edge.first] = currentDist + edge.second;
|
||||
pq[0].push(std::make_pair(dist[0][edge.first], edge.first));
|
||||
}
|
||||
}
|
||||
// store the processed node/ vertex
|
||||
workset.push_back(currentNode);
|
||||
|
||||
/// check if currentNode has already been visited
|
||||
if (visited[currentNode] == 1) {
|
||||
return Shortest_Path_Distance(workset, dist);
|
||||
}
|
||||
visited[currentNode] = true;
|
||||
/// reversed search
|
||||
|
||||
// If pq[1].size() is equal to zero then the node/ vertex is not
|
||||
// reachable from t
|
||||
if (pq[1].size() == 0) {
|
||||
break;
|
||||
}
|
||||
/// second element of pair denotes the node / vertex
|
||||
currentNode = pq[1].top().second;
|
||||
|
||||
/// first element of pair denotes the distance
|
||||
currentDist = pq[1].top().first;
|
||||
|
||||
pq[1].pop();
|
||||
|
||||
/// for all the reachable vertex from the currently exploring vertex
|
||||
/// we will try to minimize the distance
|
||||
for (std::pair<int, int> edge : (*adj2)[currentNode]) {
|
||||
/// minimizing distances
|
||||
if (currentDist + edge.second < dist[1][edge.first]) {
|
||||
dist[1][edge.first] = currentDist + edge.second;
|
||||
pq[1].push(std::make_pair(dist[1][edge.first], edge.first));
|
||||
}
|
||||
}
|
||||
// store the processed node/ vertex
|
||||
workset.push_back(currentNode);
|
||||
|
||||
/// check if currentNode has already been visited
|
||||
if (visited[currentNode] == 1) {
|
||||
return Shortest_Path_Distance(workset, dist);
|
||||
}
|
||||
visited[currentNode] = true;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} // namespace bidirectional_dijkstra
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* provided algorithm above
|
||||
* @returns void
|
||||
*/
|
||||
static void tests() {
|
||||
std::cout << "Initiatinig Predefined Tests..." << std::endl;
|
||||
std::cout << "Initiating Test 1..." << std::endl;
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj1_1(
|
||||
4, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj1_2(
|
||||
4, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 1, 2, 1);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 4, 1, 2);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 2, 3, 2);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 1, 3, 5);
|
||||
|
||||
uint64_t s = 1, t = 3;
|
||||
assert(graph::bidirectional_dijkstra::Bidijkstra(&adj1_1, &adj1_2, s - 1,
|
||||
t - 1) == 3);
|
||||
std::cout << "Test 1 Passed..." << std::endl;
|
||||
|
||||
s = 4, t = 3;
|
||||
std::cout << "Initiating Test 2..." << std::endl;
|
||||
assert(graph::bidirectional_dijkstra::Bidijkstra(&adj1_1, &adj1_2, s - 1,
|
||||
t - 1) == 5);
|
||||
std::cout << "Test 2 Passed..." << std::endl;
|
||||
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj2_1(
|
||||
5, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj2_2(
|
||||
5, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 1, 2, 4);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 1, 3, 2);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 3, 2);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 2, 1);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 4, 2);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 5, 4);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 5, 4, 1);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 5, 3);
|
||||
graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 4, 4);
|
||||
|
||||
s = 1, t = 5;
|
||||
std::cout << "Initiating Test 3..." << std::endl;
|
||||
assert(graph::bidirectional_dijkstra::Bidijkstra(&adj2_1, &adj2_2, s - 1,
|
||||
t - 1) == 6);
|
||||
std::cout << "Test 3 Passed..." << std::endl;
|
||||
std::cout << "All Test Passed..." << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // running predefined tests
|
||||
uint64_t vertices = uint64_t();
|
||||
uint64_t edges = uint64_t();
|
||||
std::cout << "Enter the number of vertices : ";
|
||||
std::cin >> vertices;
|
||||
std::cout << "Enter the number of edges : ";
|
||||
std::cin >> edges;
|
||||
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj1(
|
||||
vertices, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>> adj2(
|
||||
vertices, std::vector<std::pair<uint64_t, uint64_t>>());
|
||||
|
||||
uint64_t u = uint64_t(), v = uint64_t(), w = uint64_t();
|
||||
std::cout << "Enter the edges by three integers in this form: u v w "
|
||||
<< std::endl;
|
||||
std::cout << "Example: if there is and edge between node 1 and node 4 with "
|
||||
"weight 7 enter: 1 4 7, and then press enter"
|
||||
<< std::endl;
|
||||
while (edges--) {
|
||||
std::cin >> u >> v >> w;
|
||||
graph::bidirectional_dijkstra::addEdge(&adj1, &adj2, u, v, w);
|
||||
if (edges != 0) {
|
||||
std::cout << "Enter the next edge" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t s = uint64_t(), t = uint64_t();
|
||||
std::cout
|
||||
<< "Enter the source node and the target node separated by a space"
|
||||
<< std::endl;
|
||||
std::cout << "Example: If the source node is 5 and the target node is 6 "
|
||||
"enter: 5 6 and press enter"
|
||||
<< std::endl;
|
||||
std::cin >> s >> t;
|
||||
int dist =
|
||||
graph::bidirectional_dijkstra::Bidijkstra(&adj1, &adj2, s - 1, t - 1);
|
||||
if (dist == -1) {
|
||||
std::cout << "Target not reachable from source" << std::endl;
|
||||
} else {
|
||||
std::cout << "Shortest Path Distance : " << dist << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Breadth First Search Algorithm
|
||||
* (Breadth First Search)](https://en.wikipedia.org/wiki/Breadth-first_search)
|
||||
*
|
||||
* \author [Ayaan Khan](https://github.com/ayaankhan98)
|
||||
* \author [Aman Kumar Pandey](https://github.com/gpamangkp)
|
||||
*
|
||||
*
|
||||
* \details
|
||||
* Breadth First Search also quoted as BFS is a Graph Traversal Algorithm.
|
||||
* Time Complexity O(|V| + |E|) where V are the number of vertices and E
|
||||
* are the number of edges in the graph.
|
||||
*
|
||||
* Applications of Breadth First Search are
|
||||
*
|
||||
* 1. Finding shortest path between two vertices say u and v, with path
|
||||
* length measured by number of edges (an advantage over depth first
|
||||
* search algorithm)
|
||||
* 2. Ford-Fulkerson Method for computing the maximum flow in a flow network.
|
||||
* 3. Testing bipartiteness of a graph.
|
||||
* 4. Cheney's Algorithm, Copying garbage collection.
|
||||
*
|
||||
* And there are many more...
|
||||
*
|
||||
* <h4>working</h4>
|
||||
* In the implementation below we first created a graph using the adjacency
|
||||
* list representation of graph.
|
||||
* Breadth First Search Works as follows
|
||||
* it requires a vertex as a start vertex, Start vertex is that vertex
|
||||
* from where you want to start traversing the graph.
|
||||
* We maintain a bool array or a vector to keep track of the vertices
|
||||
* which we have visited so that we do not traverse the visited vertices
|
||||
* again and again and eventually fall into an infinite loop. Along with this
|
||||
* boolen array we use a Queue.
|
||||
*
|
||||
* 1. First we mark the start vertex as visited.
|
||||
* 2. Push this visited vertex in the Queue.
|
||||
* 3. while the queue is not empty we repeat the following steps
|
||||
*
|
||||
* 1. Take out an element from the front of queue
|
||||
* 2. Explore the adjacency list of this vertex
|
||||
* if element in the adjacency list is not visited then we
|
||||
* push that element into the queue and mark this as visited
|
||||
*
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* \namespace graph
|
||||
* \brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/* Class Graph definition */
|
||||
template <typename T>
|
||||
class Graph {
|
||||
/**
|
||||
* adjacency_list maps every vertex to the list of its neighbours in the
|
||||
* order in which they are added.
|
||||
*/
|
||||
std::map<T, std::list<T> > adjacency_list;
|
||||
|
||||
public:
|
||||
Graph() = default;
|
||||
;
|
||||
void add_edge(T u, T v, bool bidir = true) {
|
||||
/**
|
||||
* add_edge(u,v,bidir) is used to add an edge between node u and
|
||||
* node v by default , bidir is made true , i.e graph is
|
||||
* bidirectional . It means if edge(u,v) is added then u-->v and
|
||||
* v-->u both edges exist.
|
||||
*
|
||||
* to make the graph unidirectional pass the third parameter of
|
||||
* add_edge as false which will
|
||||
*/
|
||||
adjacency_list[u].push_back(v); // u-->v edge added
|
||||
if (bidir == true) {
|
||||
// if graph is bidirectional
|
||||
adjacency_list[v].push_back(u); // v-->u edge added
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this function performs the breadth first search on graph and return a
|
||||
* mapping which maps the nodes to a boolean value representing whether the
|
||||
* node was traversed or not.
|
||||
*/
|
||||
std::map<T, bool> breadth_first_search(T src) {
|
||||
/// mapping to keep track of all visited nodes
|
||||
std::map<T, bool> visited;
|
||||
/// initialise every possible vertex to map to false
|
||||
/// initially none of the vertices are unvisited
|
||||
for (auto const &adjlist : adjacency_list) {
|
||||
visited[adjlist.first] = false;
|
||||
for (auto const &node : adjacency_list[adjlist.first]) {
|
||||
visited[node] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// queue to store the nodes which are yet to be traversed
|
||||
std::queue<T> tracker;
|
||||
|
||||
/// push the source vertex to queue to begin traversing
|
||||
tracker.push(src);
|
||||
/// mark the source vertex as visited
|
||||
visited[src] = true;
|
||||
while (!tracker.empty()) {
|
||||
/// traverse the graph till no connected vertex are left
|
||||
/// extract a node from queue for further traversal
|
||||
T node = tracker.front();
|
||||
/// remove the node from the queue
|
||||
tracker.pop();
|
||||
for (T const &neighbour : adjacency_list[node]) {
|
||||
/// check every vertex connected to the node which are still
|
||||
/// unvisited
|
||||
if (!visited[neighbour]) {
|
||||
/// if the neighbour is unvisited , push it into the queue
|
||||
tracker.push(neighbour);
|
||||
/// mark the neighbour as visited
|
||||
visited[neighbour] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
};
|
||||
/* Class definition ends */
|
||||
} // namespace graph
|
||||
|
||||
/** Test function */
|
||||
static void tests() {
|
||||
/// Test 1 Begin
|
||||
graph::Graph<int> g;
|
||||
std::map<int, bool> correct_result;
|
||||
g.add_edge(0, 1);
|
||||
g.add_edge(1, 2);
|
||||
g.add_edge(2, 3);
|
||||
correct_result[0] = true;
|
||||
correct_result[1] = true;
|
||||
correct_result[2] = true;
|
||||
correct_result[3] = true;
|
||||
|
||||
std::map<int, bool> returned_result = g.breadth_first_search(2);
|
||||
|
||||
assert(returned_result == correct_result);
|
||||
std::cout << "Test 1 Passed..." << std::endl;
|
||||
|
||||
/// Test 2 Begin
|
||||
returned_result = g.breadth_first_search(0);
|
||||
|
||||
assert(returned_result == correct_result);
|
||||
std::cout << "Test 2 Passed..." << std::endl;
|
||||
|
||||
/// Test 3 Begins
|
||||
graph::Graph<std::string> g2;
|
||||
|
||||
g2.add_edge("Gorakhpur", "Lucknow", false);
|
||||
g2.add_edge("Gorakhpur", "Kanpur", false);
|
||||
g2.add_edge("Lucknow", "Agra", false);
|
||||
g2.add_edge("Kanpur", "Agra", false);
|
||||
g2.add_edge("Lucknow", "Prayagraj", false);
|
||||
g2.add_edge("Agra", "Noida", false);
|
||||
|
||||
std::map<std::string, bool> correct_res;
|
||||
std::map<std::string, bool> returned_res =
|
||||
g2.breadth_first_search("Kanpur");
|
||||
correct_res["Gorakhpur"] = false;
|
||||
correct_res["Lucknow"] = false;
|
||||
correct_res["Kanpur"] = true;
|
||||
correct_res["Agra"] = true;
|
||||
correct_res["Prayagraj"] = false;
|
||||
correct_res["Noida"] = true;
|
||||
assert(correct_res == returned_res);
|
||||
std::cout << "Test 3 Passed..." << std::endl;
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
tests();
|
||||
size_t edges = 0;
|
||||
std::cout << "Enter the number of edges: ";
|
||||
std::cin >> edges;
|
||||
|
||||
graph::Graph<int> g;
|
||||
|
||||
std::cout << "Enter space-separated pairs of vertices that form edges: "
|
||||
<< std::endl;
|
||||
while (edges--) {
|
||||
int u = 0, v = 0;
|
||||
std::cin >> u >> v;
|
||||
g.add_edge(u, v);
|
||||
}
|
||||
|
||||
g.breadth_first_search(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright : 2020 , MIT
|
||||
* Author : Amit Kumar (offamitkumar)
|
||||
* Last Modified Date: May 24, 2020
|
||||
*
|
||||
*/
|
||||
#include <algorithm> // for min & max
|
||||
#include <iostream> // for cout
|
||||
#include <vector> // for std::vector
|
||||
|
||||
class Solution {
|
||||
std::vector<std::vector<int>> graph;
|
||||
std::vector<int> in_time, out_time;
|
||||
int timer = 0;
|
||||
std::vector<std::vector<int>> bridge;
|
||||
std::vector<bool> visited;
|
||||
void dfs(int current_node, int parent) {
|
||||
visited.at(current_node) = true;
|
||||
in_time[current_node] = out_time[current_node] = timer++;
|
||||
for (auto& itr : graph[current_node]) {
|
||||
if (itr == parent) {
|
||||
continue;
|
||||
}
|
||||
if (!visited[itr]) {
|
||||
dfs(itr, current_node);
|
||||
if (out_time[itr] > in_time[current_node]) {
|
||||
bridge.push_back({itr, current_node});
|
||||
}
|
||||
}
|
||||
out_time[current_node] =
|
||||
std::min(out_time[current_node], out_time[itr]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<std::vector<int>> search_bridges(
|
||||
int n, const std::vector<std::vector<int>>& connections) {
|
||||
timer = 0;
|
||||
graph.resize(n);
|
||||
in_time.assign(n, 0);
|
||||
visited.assign(n, false);
|
||||
out_time.assign(n, 0);
|
||||
for (auto& itr : connections) {
|
||||
graph.at(itr[0]).push_back(itr[1]);
|
||||
graph.at(itr[1]).push_back(itr[0]);
|
||||
}
|
||||
dfs(0, -1);
|
||||
return bridge;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
int main() {
|
||||
Solution s1;
|
||||
int number_of_node = 5;
|
||||
std::vector<std::vector<int>> node;
|
||||
node.push_back({0, 1});
|
||||
node.push_back({1, 3});
|
||||
node.push_back({1, 2});
|
||||
node.push_back({2, 4});
|
||||
/*
|
||||
* 0 <--> 1 <---> 2
|
||||
* ^ ^
|
||||
* | |
|
||||
* | |
|
||||
* \/ \/
|
||||
* 3 4
|
||||
*
|
||||
* In this graph there are 4 bridges [0,2] , [2,4] , [3,5] , [1,2]
|
||||
*
|
||||
* I assumed that the graph is bi-directional and connected.
|
||||
*
|
||||
*/
|
||||
std::vector<std::vector<int>> bridges =
|
||||
s1.search_bridges(number_of_node, node);
|
||||
std::cout << bridges.size() << " bridges found!\n";
|
||||
for (auto& itr : bridges) {
|
||||
std::cout << itr[0] << " --> " << itr[1] << '\n';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Graph Connected Components
|
||||
* (Connected Components)]
|
||||
* (https://en.wikipedia.org/wiki/Component_(graph_theory))
|
||||
*
|
||||
* \author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
*
|
||||
* \details
|
||||
* A graph is a collection of nodes also called vertices and these vertices
|
||||
* are connected by edges. A connected component in a graph refers to a set of
|
||||
* vertices which are reachable form one another.
|
||||
*
|
||||
* <pre>
|
||||
* Example - Here is graph with 3 connected components
|
||||
*
|
||||
* 1 4 5 8
|
||||
* / \ / / \ / \
|
||||
* 2---3 6 7 9 10
|
||||
*
|
||||
* first second third
|
||||
* component component component
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph Algorithms
|
||||
*/
|
||||
|
||||
namespace graph {
|
||||
/**
|
||||
* @brief Function that add edge between two nodes or vertices of graph
|
||||
*
|
||||
* @param adj adjacency list of graph.
|
||||
* @param u any node or vertex of graph.
|
||||
* @param v any node or vertex of graph.
|
||||
*/
|
||||
void addEdge(std::vector<std::vector<int>> *adj, int u, int v) {
|
||||
(*adj)[u - 1].push_back(v - 1);
|
||||
(*adj)[v - 1].push_back(u - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function for depth first seach algorithm
|
||||
* this function explores the vertex which is passed into.
|
||||
*
|
||||
* @param adj adjacency list of graph.
|
||||
* @param u vertex or node to be explored.
|
||||
* @param visited already visited vertices.
|
||||
*/
|
||||
void explore(const std::vector<std::vector<int>> *adj, int u,
|
||||
std::vector<bool> *visited) {
|
||||
(*visited)[u] = true;
|
||||
for (auto v : (*adj)[u]) {
|
||||
if (!(*visited)[v]) {
|
||||
explore(adj, v, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function that perfoms depth first search algorithm on graph
|
||||
* and calculated the number of connected components.
|
||||
*
|
||||
* @param adj adjacency list of graph.
|
||||
*
|
||||
* @return connected_components number of connected components in graph.
|
||||
*/
|
||||
int getConnectedComponents(const std::vector<std::vector<int>> *adj) {
|
||||
int n = adj->size();
|
||||
int connected_components = 0;
|
||||
std::vector<bool> visited(n, false);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!visited[i]) {
|
||||
explore(adj, i, &visited);
|
||||
connected_components++;
|
||||
}
|
||||
}
|
||||
return connected_components;
|
||||
}
|
||||
} // namespace graph
|
||||
|
||||
/** Function to test the algorithm */
|
||||
void tests() {
|
||||
std::cout << "Running predefined tests..." << std::endl;
|
||||
std::cout << "Initiating Test 1..." << std::endl;
|
||||
std::vector<std::vector<int>> adj1(9, std::vector<int>());
|
||||
graph::addEdge(&adj1, 1, 2);
|
||||
graph::addEdge(&adj1, 1, 3);
|
||||
graph::addEdge(&adj1, 3, 4);
|
||||
graph::addEdge(&adj1, 5, 7);
|
||||
graph::addEdge(&adj1, 5, 6);
|
||||
graph::addEdge(&adj1, 8, 9);
|
||||
|
||||
assert(graph::getConnectedComponents(&adj1) == 3);
|
||||
std::cout << "Test 1 Passed..." << std::endl;
|
||||
|
||||
std::cout << "Innitiating Test 2..." << std::endl;
|
||||
std::vector<std::vector<int>> adj2(10, std::vector<int>());
|
||||
graph::addEdge(&adj2, 1, 2);
|
||||
graph::addEdge(&adj2, 1, 3);
|
||||
graph::addEdge(&adj2, 1, 4);
|
||||
graph::addEdge(&adj2, 2, 3);
|
||||
graph::addEdge(&adj2, 3, 4);
|
||||
graph::addEdge(&adj2, 4, 8);
|
||||
graph::addEdge(&adj2, 4, 10);
|
||||
graph::addEdge(&adj2, 8, 10);
|
||||
graph::addEdge(&adj2, 8, 9);
|
||||
graph::addEdge(&adj2, 5, 7);
|
||||
graph::addEdge(&adj2, 5, 6);
|
||||
graph::addEdge(&adj2, 6, 7);
|
||||
|
||||
assert(graph::getConnectedComponents(&adj2) == 2);
|
||||
std::cout << "Test 2 Passed..." << std::endl;
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
/// running predefined tests
|
||||
tests();
|
||||
|
||||
int vertices = int(), edges = int();
|
||||
std::cout << "Enter the number of vertices : ";
|
||||
std::cin >> vertices;
|
||||
std::cout << "Enter the number of edges : ";
|
||||
std::cin >> edges;
|
||||
|
||||
std::vector<std::vector<int>> adj(vertices, std::vector<int>());
|
||||
|
||||
int u = int(), v = int();
|
||||
while (edges--) {
|
||||
std::cin >> u >> v;
|
||||
graph::addEdge(&adj, u, v);
|
||||
}
|
||||
|
||||
int cc = graph::getConnectedComponents(&adj);
|
||||
std::cout << cc << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Disjoint union](https://en.wikipedia.org/wiki/Disjoint_union)
|
||||
*
|
||||
* @details
|
||||
* The Disjoint union is the technique to find connected component in graph
|
||||
* efficiently.
|
||||
*
|
||||
* ### Algorithm
|
||||
* In Graph, if you have to find out the number of connected components, there
|
||||
* are 2 options
|
||||
* 1. Depth first search
|
||||
* 2. Disjoint union
|
||||
* 1st option is inefficient, Disjoint union is the most optimal way to find
|
||||
* this.
|
||||
*
|
||||
* @author Unknown author
|
||||
* @author [Sagar Pandya](https://github.com/sagarpandyansit)
|
||||
*/
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <set> /// for std::set
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph Algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @namespace disjoint_union
|
||||
* @brief Functions for [Disjoint
|
||||
* union](https://en.wikipedia.org/wiki/Disjoint_union) implementation
|
||||
*/
|
||||
namespace disjoint_union {
|
||||
uint32_t number_of_nodes = 0; // denotes number of nodes
|
||||
std::vector<int64_t> parent{}; // parent of each node
|
||||
std::vector<uint32_t> connected_set_size{}; // size of each set
|
||||
/**
|
||||
* @brief function the initialize every node as it's own parent
|
||||
* @returns void
|
||||
*/
|
||||
void make_set() {
|
||||
for (uint32_t i = 1; i <= number_of_nodes; i++) {
|
||||
parent[i] = i;
|
||||
connected_set_size[i] = 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Find the component where following node belongs to
|
||||
* @param val parent of val should be found
|
||||
* @return parent of val
|
||||
*/
|
||||
int64_t find_set(int64_t val) {
|
||||
while (parent[val] != val) {
|
||||
parent[val] = parent[parent[val]];
|
||||
val = parent[val];
|
||||
}
|
||||
return val;
|
||||
}
|
||||
/**
|
||||
* @brief Merge 2 components to become one
|
||||
* @param node1 1st component
|
||||
* @param node2 2nd component
|
||||
* @returns void
|
||||
*/
|
||||
void union_sets(int64_t node1, int64_t node2) {
|
||||
node1 = find_set(node1); // find the parent of node1
|
||||
node2 = find_set(node2); // find the parent of node2
|
||||
|
||||
// If parents of both nodes are not same, combine them
|
||||
if (node1 != node2) {
|
||||
if (connected_set_size[node1] < connected_set_size[node2]) {
|
||||
std::swap(node1, node2); // swap both components
|
||||
}
|
||||
parent[node2] = node1; // make node1 as parent of node2.
|
||||
connected_set_size[node1] +=
|
||||
connected_set_size[node2]; // sum the size of both as they combined
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Find total no. of connected components
|
||||
* @return Number of connected components
|
||||
*/
|
||||
uint32_t no_of_connected_components() {
|
||||
std::set<int64_t> temp; // temp set to count number of connected components
|
||||
for (uint32_t i = 1; i <= number_of_nodes; i++) temp.insert(find_set(i));
|
||||
return temp.size(); // return the size of temp set
|
||||
}
|
||||
} // namespace disjoint_union
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Test Implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
namespace dsu = graph::disjoint_union;
|
||||
std::cin >> dsu::number_of_nodes;
|
||||
dsu::parent.resize(dsu::number_of_nodes + 1);
|
||||
dsu::connected_set_size.resize(dsu::number_of_nodes + 1);
|
||||
dsu::make_set();
|
||||
uint32_t edges = 0;
|
||||
std::cin >> edges; // no of edges in the graph
|
||||
while (edges--) {
|
||||
int64_t node_a = 0, node_b = 0;
|
||||
std::cin >> node_a >> node_b;
|
||||
dsu::union_sets(node_a, node_b);
|
||||
}
|
||||
std::cout << dsu::no_of_connected_components() << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // Execute the tests
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* @file cycle_check_directed graph.cpp
|
||||
*
|
||||
* @brief BFS and DFS algorithms to check for cycle in a directed graph.
|
||||
*
|
||||
* @author [Anmol3299](mailto:mittalanmol22@gmail.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream> // for std::cout
|
||||
#include <map> // for std::map
|
||||
#include <queue> // for std::queue
|
||||
#include <stdexcept> // for throwing errors
|
||||
#include <type_traits> // for std::remove_reference
|
||||
#include <utility> // for std::move
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/**
|
||||
* Implementation of non-weighted directed edge of a graph.
|
||||
*
|
||||
* The source vertex of the edge is labelled "src" and destination vertex is
|
||||
* labelled "dest".
|
||||
*/
|
||||
struct Edge {
|
||||
unsigned int src;
|
||||
unsigned int dest;
|
||||
|
||||
Edge() = delete;
|
||||
~Edge() = default;
|
||||
Edge(Edge&&) = default;
|
||||
Edge& operator=(Edge&&) = default;
|
||||
Edge(Edge const&) = default;
|
||||
Edge& operator=(Edge const&) = default;
|
||||
|
||||
/** Set the source and destination of the vertex.
|
||||
*
|
||||
* @param source is the source vertex of the edge.
|
||||
* @param destination is the destination vertex of the edge.
|
||||
*/
|
||||
Edge(unsigned int source, unsigned int destination)
|
||||
: src(source), dest(destination) {}
|
||||
};
|
||||
|
||||
using AdjList = std::map<unsigned int, std::vector<unsigned int>>;
|
||||
|
||||
/**
|
||||
* Implementation of graph class.
|
||||
*
|
||||
* The graph will be represented using Adjacency List representation.
|
||||
* This class contains 2 data members "m_vertices" & "m_adjList" used to
|
||||
* represent the number of vertices and adjacency list of the graph
|
||||
* respectively. The vertices are labelled 0 - (m_vertices - 1).
|
||||
*/
|
||||
class Graph {
|
||||
public:
|
||||
Graph() : m_adjList({}) {}
|
||||
~Graph() = default;
|
||||
Graph(Graph&&) = default;
|
||||
Graph& operator=(Graph&&) = default;
|
||||
Graph(Graph const&) = default;
|
||||
Graph& operator=(Graph const&) = default;
|
||||
|
||||
/** Create a graph from vertices and adjacency list.
|
||||
*
|
||||
* @param vertices specify the number of vertices the graph would contain.
|
||||
* @param adjList is the adjacency list representation of graph.
|
||||
*/
|
||||
Graph(unsigned int vertices, AdjList adjList)
|
||||
: m_vertices(vertices), m_adjList(std::move(adjList)) {}
|
||||
|
||||
/** Create a graph from vertices and adjacency list.
|
||||
*
|
||||
* @param vertices specify the number of vertices the graph would contain.
|
||||
* @param adjList is the adjacency list representation of graph.
|
||||
*/
|
||||
Graph(unsigned int vertices, AdjList&& adjList)
|
||||
: m_vertices(vertices), m_adjList(std::move(adjList)) {}
|
||||
|
||||
/** Create a graph from vertices and a set of edges.
|
||||
*
|
||||
* Adjacency list of the graph would be created from the set of edges. If
|
||||
* the source or destination of any edge has a value greater or equal to
|
||||
* number of vertices, then it would throw a range_error.
|
||||
*
|
||||
* @param vertices specify the number of vertices the graph would contain.
|
||||
* @param edges is a vector of edges.
|
||||
*/
|
||||
Graph(unsigned int vertices, std::vector<Edge> const& edges)
|
||||
: m_vertices(vertices) {
|
||||
for (auto const& edge : edges) {
|
||||
if (edge.src >= vertices || edge.dest >= vertices) {
|
||||
throw std::range_error(
|
||||
"Either src or dest of edge out of range");
|
||||
}
|
||||
m_adjList[edge.src].emplace_back(edge.dest);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return a const reference of the adjacency list.
|
||||
*
|
||||
* @return const reference to the adjacency list
|
||||
*/
|
||||
std::remove_reference<AdjList>::type const& getAdjList() const {
|
||||
return m_adjList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of vertices in the graph.
|
||||
*/
|
||||
unsigned int getVertices() const { return m_vertices; }
|
||||
|
||||
/** Add vertices in the graph.
|
||||
*
|
||||
* @param num is the number of vertices to be added. It adds 1 vertex by
|
||||
* default.
|
||||
*
|
||||
*/
|
||||
void addVertices(unsigned int num = 1) { m_vertices += num; }
|
||||
|
||||
/** Add an edge in the graph.
|
||||
*
|
||||
* @param edge that needs to be added.
|
||||
*/
|
||||
void addEdge(Edge const& edge) {
|
||||
if (edge.src >= m_vertices || edge.dest >= m_vertices) {
|
||||
throw std::range_error("Either src or dest of edge out of range");
|
||||
}
|
||||
m_adjList[edge.src].emplace_back(edge.dest);
|
||||
}
|
||||
|
||||
/** Add an Edge in the graph
|
||||
*
|
||||
* @param source is source vertex of the edge.
|
||||
* @param destination is the destination vertex of the edge.
|
||||
*/
|
||||
void addEdge(unsigned int source, unsigned int destination) {
|
||||
if (source >= m_vertices || destination >= m_vertices) {
|
||||
throw std::range_error(
|
||||
"Either source or destination of edge out of range");
|
||||
}
|
||||
m_adjList[source].emplace_back(destination);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_vertices = 0;
|
||||
AdjList m_adjList;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a directed graph has a cycle or not.
|
||||
*
|
||||
* This class provides 2 methods to check for cycle in a directed graph:
|
||||
* isCyclicDFS & isCyclicBFS.
|
||||
*
|
||||
* - isCyclicDFS uses DFS traversal method to check for cycle in a graph.
|
||||
* - isCyclidBFS used BFS traversal method to check for cycle in a graph.
|
||||
*/
|
||||
class CycleCheck {
|
||||
private:
|
||||
enum nodeStates : uint8_t { not_visited = 0, in_stack, visited };
|
||||
|
||||
/** Helper function of "isCyclicDFS".
|
||||
*
|
||||
* @param adjList is the adjacency list representation of some graph.
|
||||
* @param state is the state of the nodes of the graph.
|
||||
* @param node is the node being evaluated.
|
||||
*
|
||||
* @return true if graph has a cycle, else false.
|
||||
*/
|
||||
static bool isCyclicDFSHelper(AdjList const& adjList,
|
||||
std::vector<nodeStates>* state,
|
||||
unsigned int node) {
|
||||
// Add node "in_stack" state.
|
||||
(*state)[node] = in_stack;
|
||||
|
||||
// If the node has children, then recursively visit all children of the
|
||||
// node.
|
||||
auto const it = adjList.find(node);
|
||||
if (it != adjList.end()) {
|
||||
for (auto child : it->second) {
|
||||
// If state of child node is "not_visited", evaluate that child
|
||||
// for presence of cycle.
|
||||
auto state_of_child = (*state)[child];
|
||||
if (state_of_child == not_visited) {
|
||||
if (isCyclicDFSHelper(adjList, state, child)) {
|
||||
return true;
|
||||
}
|
||||
} else if (state_of_child == in_stack) {
|
||||
// If child node was "in_stack", then that means that there
|
||||
// is a cycle in the graph. Return true for presence of the
|
||||
// cycle.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Current node has been evaluated for the presence of cycle and had no
|
||||
// cycle. Mark current node as "visited".
|
||||
(*state)[node] = visited;
|
||||
// Return that current node didn't result in any cycles.
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
/** Driver function to check if a graph has a cycle.
|
||||
*
|
||||
* This function uses DFS to check for cycle in the graph.
|
||||
*
|
||||
* @param graph which needs to be evaluated for the presence of cycle.
|
||||
* @return true if a cycle is detected, else false.
|
||||
*/
|
||||
static bool isCyclicDFS(Graph const& graph) {
|
||||
auto vertices = graph.getVertices();
|
||||
|
||||
/** State of the node.
|
||||
*
|
||||
* It is a vector of "nodeStates" which represents the state node is in.
|
||||
* It can take only 3 values: "not_visited", "in_stack", and "visited".
|
||||
*
|
||||
* Initially, all nodes are in "not_visited" state.
|
||||
*/
|
||||
std::vector<nodeStates> state(vertices, not_visited);
|
||||
|
||||
// Start visiting each node.
|
||||
for (unsigned int node = 0; node < vertices; node++) {
|
||||
// If a node is not visited, only then check for presence of cycle.
|
||||
// There is no need to check for presence of cycle for a visited
|
||||
// node as it has already been checked for presence of cycle.
|
||||
if (state[node] == not_visited) {
|
||||
// Check for cycle.
|
||||
if (isCyclicDFSHelper(graph.getAdjList(), &state, node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All nodes have been safely traversed, that means there is no cycle in
|
||||
// the graph. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Check if a graph has cycle or not.
|
||||
*
|
||||
* This function uses BFS to check if a graph is cyclic or not.
|
||||
*
|
||||
* @param graph which needs to be evaluated for the presence of cycle.
|
||||
* @return true if a cycle is detected, else false.
|
||||
*/
|
||||
static bool isCyclicBFS(Graph const& graph) {
|
||||
auto graphAjdList = graph.getAdjList();
|
||||
auto vertices = graph.getVertices();
|
||||
|
||||
std::vector<unsigned int> indegree(vertices, 0);
|
||||
// Calculate the indegree i.e. the number of incident edges to the node.
|
||||
for (auto const& list : graphAjdList) {
|
||||
auto children = list.second;
|
||||
for (auto const& child : children) {
|
||||
indegree[child]++;
|
||||
}
|
||||
}
|
||||
|
||||
std::queue<unsigned int> can_be_solved;
|
||||
for (unsigned int node = 0; node < vertices; node++) {
|
||||
// If a node doesn't have any input edges, then that node will
|
||||
// definately not result in a cycle and can be visited safely.
|
||||
if (!indegree[node]) {
|
||||
can_be_solved.emplace(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices that need to be traversed.
|
||||
auto remain = vertices;
|
||||
// While there are safe nodes that we can visit.
|
||||
while (!can_be_solved.empty()) {
|
||||
auto solved = can_be_solved.front();
|
||||
// Visit the node.
|
||||
can_be_solved.pop();
|
||||
// Decrease number of nodes that need to be traversed.
|
||||
remain--;
|
||||
|
||||
// Visit all the children of the visited node.
|
||||
auto it = graphAjdList.find(solved);
|
||||
if (it != graphAjdList.end()) {
|
||||
for (auto child : it->second) {
|
||||
// Check if we can visited the node safely.
|
||||
if (--indegree[child] == 0) {
|
||||
// if node can be visited safely, then add that node to
|
||||
// the visit queue.
|
||||
can_be_solved.emplace(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are still nodes that we can't visit, then it means that
|
||||
// there is a cycle and return true, else return false.
|
||||
return !(remain == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function.
|
||||
*/
|
||||
int main() {
|
||||
// Instantiate the graph.
|
||||
Graph g(7, std::vector<Edge>{{0, 1}, {1, 2}, {2, 0}, {2, 5}, {3, 5}});
|
||||
// Check for cycle using BFS method.
|
||||
std::cout << CycleCheck::isCyclicBFS(g) << '\n';
|
||||
|
||||
// Check for cycle using DFS method.
|
||||
std::cout << CycleCheck::isCyclicDFS(g) << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Depth First Search Algorithm
|
||||
* (Depth First Search)](https://en.wikipedia.org/wiki/Depth-first_search)
|
||||
*
|
||||
* \author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
*
|
||||
* \details
|
||||
* Depth First Search also quoted as DFS is a Graph Traversal Algorithm.
|
||||
* Time Complexity O(|V| + |E|) where V is number of vertices and E
|
||||
* is number of edges in graph.
|
||||
*
|
||||
* Application of Depth First Search are
|
||||
*
|
||||
* 1. Finding connected components
|
||||
* 2. Finding 2-(edge or vertex)-connected components.
|
||||
* 3. Finding 3-(edge or vertex)-connected components.
|
||||
* 4. Finding the bridges of a graph.
|
||||
* 5. Generating words in order to plot the limit set of a group.
|
||||
* 6. Finding strongly connected components.
|
||||
*
|
||||
* And there are many more...
|
||||
*
|
||||
* <h4>Working</h4>
|
||||
* 1. Mark all vertices as unvisited first
|
||||
* 2. start exploring from some starting vertex.
|
||||
*
|
||||
* While exploring vertex we mark the vertex as visited
|
||||
* and start exploring the vertices connected to this
|
||||
* vertex in recursive way.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
*
|
||||
* \namespace graph
|
||||
* \brief Graph Algorithms
|
||||
*
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* \brief
|
||||
* Adds and edge between two vertices of graph say u and v in this
|
||||
* case.
|
||||
*
|
||||
* @param adj Adjacency list representation of graph
|
||||
* @param u first vertex
|
||||
* @param v second vertex
|
||||
*
|
||||
*/
|
||||
void addEdge(std::vector<std::vector<size_t>> *adj, size_t u, size_t v) {
|
||||
/*
|
||||
*
|
||||
* Here we are considering undirected graph that's the
|
||||
* reason we are adding v to the adjacency list representation of u
|
||||
* and also adding u to the adjacency list representation of v
|
||||
*
|
||||
*/
|
||||
(*adj)[u - 1].push_back(v - 1);
|
||||
(*adj)[v - 1].push_back(u - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \brief
|
||||
* Explores the given vertex, exploring a vertex means traversing
|
||||
* over all the vertices which are connected to the vertex that is
|
||||
* currently being explored.
|
||||
*
|
||||
* @param adj garph
|
||||
* @param v vertex to be explored
|
||||
* @param visited already visited vertices
|
||||
*
|
||||
*/
|
||||
void explore(const std::vector<std::vector<size_t>> &adj, size_t v,
|
||||
std::vector<bool> *visited) {
|
||||
std::cout << v + 1 << " ";
|
||||
(*visited)[v] = true;
|
||||
for (auto x : adj[v]) {
|
||||
if (!(*visited)[x]) {
|
||||
explore(adj, x, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* initiates depth first search algorithm.
|
||||
*
|
||||
* @param adj adjacency list of graph
|
||||
* @param start vertex from where DFS starts traversing.
|
||||
*
|
||||
*/
|
||||
void depth_first_search(const std::vector<std::vector<size_t>> &adj,
|
||||
size_t start) {
|
||||
size_t vertices = adj.size();
|
||||
|
||||
std::vector<bool> visited(vertices, false);
|
||||
explore(adj, start, &visited);
|
||||
}
|
||||
} // namespace graph
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
size_t vertices = 0, edges = 0;
|
||||
std::cout << "Enter the Vertices : ";
|
||||
std::cin >> vertices;
|
||||
std::cout << "Enter the Edges : ";
|
||||
std::cin >> edges;
|
||||
|
||||
/// creating graph
|
||||
std::vector<std::vector<size_t>> adj(vertices, std::vector<size_t>());
|
||||
|
||||
/// taking input for edges
|
||||
std::cout << "Enter the vertices which have edges between them : "
|
||||
<< std::endl;
|
||||
while (edges--) {
|
||||
size_t u = 0, v = 0;
|
||||
std::cin >> u >> v;
|
||||
graph::addEdge(&adj, u, v);
|
||||
}
|
||||
|
||||
/// running depth first search over graph
|
||||
graph::depth_first_search(adj, 2);
|
||||
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
*
|
||||
* @file
|
||||
* @brief [Depth First Search Algorithm using Stack
|
||||
* (Depth First Search Algorithm)](https://en.wikipedia.org/wiki/Depth-first_search)
|
||||
*
|
||||
* @author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
* @author [Saurav Uppoor](https://github.com/sauravUppoor)
|
||||
*
|
||||
* @details
|
||||
* Depth First Search also quoted as DFS is a Graph Traversal Algorithm.
|
||||
* Time Complexity O(|V| + |E|) where V is number of vertices and E
|
||||
* is number of edges in graph.
|
||||
*
|
||||
* Application of Depth First Search are
|
||||
*
|
||||
* 1. Finding connected components
|
||||
* 2. Finding 2-(edge or vertex)-connected components.
|
||||
* 3. Finding 3-(edge or vertex)-connected components.
|
||||
* 4. Finding the bridges of a graph.
|
||||
* 5. Generating words in order to plot the limit set of a group.
|
||||
* 6. Finding strongly connected components.
|
||||
*
|
||||
* <h4>Working</h4>
|
||||
* 1. Mark all vertices as unvisited (colour it WHITE).
|
||||
* 2. Push starting vertex into the stack and colour it GREY.
|
||||
* 3. Once a node is popped out of the stack and is coloured GREY, we colour it BLACK.
|
||||
* 4. Push all its neighbours which are not coloured BLACK.
|
||||
* 5. Repeat steps 4 and 5 until the stack is empty.
|
||||
*/
|
||||
|
||||
#include <iostream> /// for IO operations
|
||||
#include <stack> /// header for std::stack
|
||||
#include <vector> /// header for std::vector
|
||||
#include <cassert> /// header for preprocessor macro assert()
|
||||
#include <limits> /// header for limits of integral types
|
||||
|
||||
constexpr int WHITE = 0; /// indicates the node hasn't been explored
|
||||
constexpr int GREY = 1; /// indicates node is in stack waiting to be explored
|
||||
constexpr int BLACK = 2; /// indicates node has already been explored
|
||||
constexpr int64_t INF = std::numeric_limits<int16_t>::max();
|
||||
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @namespace depth_first_search
|
||||
* @brief Functions for [Depth First Search](https://en.wikipedia.org/wiki/Depth-first_search) algorithm
|
||||
*/
|
||||
namespace depth_first_search {
|
||||
/**
|
||||
* @brief
|
||||
* Adds and edge between two vertices of graph say u and v in this
|
||||
* case.
|
||||
*
|
||||
* @param adj Adjacency list representation of graph
|
||||
* @param u first vertex
|
||||
* @param v second vertex
|
||||
*
|
||||
*/
|
||||
void addEdge(std::vector<std::vector<size_t>> *adj, size_t u, size_t v) {
|
||||
/*
|
||||
*
|
||||
* Here we are considering undirected graph that's the
|
||||
* reason we are adding v to the adjacency list representation of u
|
||||
* and also adding u to the adjacency list representation of v
|
||||
*
|
||||
*/
|
||||
(*adj)[u - 1].push_back(v - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief
|
||||
* Explores the given vertex, exploring a vertex means traversing
|
||||
* over all the vertices which are connected to the vertex that is
|
||||
* currently being explored and push it onto the stack.
|
||||
*
|
||||
* @param adj graph
|
||||
* @param start starting vertex for DFS
|
||||
* @return vector with nodes stored in the order of DFS traversal
|
||||
*
|
||||
*/
|
||||
std::vector<size_t> dfs(const std::vector<std::vector<size_t> > &graph, size_t start) {
|
||||
/// checked[i] stores the status of each node
|
||||
std::vector<size_t> checked(graph.size(), WHITE), traversed_path;
|
||||
|
||||
checked[start] = GREY;
|
||||
std::stack<size_t> stack;
|
||||
stack.push(start);
|
||||
|
||||
/// while stack is not empty we keep exploring the node on top of stack
|
||||
while (!stack.empty()) {
|
||||
int act = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if (checked[act] == GREY) {
|
||||
/// push the node to the final result vector
|
||||
traversed_path.push_back(act + 1);
|
||||
|
||||
/// exploring the neighbours of the current node
|
||||
for (auto it : graph[act]) {
|
||||
stack.push(it);
|
||||
if (checked[it] != BLACK) {
|
||||
checked[it] = GREY;
|
||||
}
|
||||
}
|
||||
checked[act] = BLACK; /// Node has been explored
|
||||
}
|
||||
}
|
||||
return traversed_path;
|
||||
}
|
||||
} // namespace depth_first_search
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* Self-test implementations
|
||||
* @returns none
|
||||
*/
|
||||
static void tests() {
|
||||
size_t start_pos;
|
||||
|
||||
/// Test 1
|
||||
std::cout << "Case 1: " << std::endl;
|
||||
start_pos = 1;
|
||||
std::vector<std::vector<size_t> > g1(3, std::vector<size_t>());
|
||||
|
||||
graph::depth_first_search::addEdge(&g1, 1, 2);
|
||||
graph::depth_first_search::addEdge(&g1, 2, 3);
|
||||
graph::depth_first_search::addEdge(&g1, 3, 1);
|
||||
|
||||
std::vector<size_t> expected1 {1, 2, 3}; /// for the above sample data, this is the expected output
|
||||
assert(graph::depth_first_search::dfs(g1, start_pos - 1) == expected1);
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
/// Test 2
|
||||
std::cout << "Case 2: " << std::endl;
|
||||
start_pos = 1;
|
||||
std::vector<std::vector<size_t> > g2(4, std::vector<size_t>());
|
||||
|
||||
graph::depth_first_search::addEdge(&g2, 1, 2);
|
||||
graph::depth_first_search::addEdge(&g2, 1, 3);
|
||||
graph::depth_first_search::addEdge(&g2, 2, 4);
|
||||
graph::depth_first_search::addEdge(&g2, 4, 1);
|
||||
|
||||
std::vector<size_t> expected2 {1, 3, 2, 4}; /// for the above sample data, this is the expected output
|
||||
assert(graph::depth_first_search::dfs(g2, start_pos - 1) == expected2);
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
/// Test 3
|
||||
std::cout << "Case 3: " << std::endl;
|
||||
start_pos = 2;
|
||||
std::vector<std::vector<size_t> > g3(4, std::vector<size_t>());
|
||||
|
||||
graph::depth_first_search::addEdge(&g3, 1, 2);
|
||||
graph::depth_first_search::addEdge(&g3, 1, 3);
|
||||
graph::depth_first_search::addEdge(&g3, 2, 4);
|
||||
graph::depth_first_search::addEdge(&g3, 4, 1);
|
||||
|
||||
std::vector<size_t> expected3 {2, 4, 1, 3}; /// for the above sample data, this is the expected output
|
||||
assert(graph::depth_first_search::dfs(g3, start_pos - 1) == expected3);
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // execute the tests
|
||||
|
||||
size_t vertices = 0, edges = 0, start_pos = 1;
|
||||
std::vector<size_t> traversal;
|
||||
|
||||
std::cout << "Enter the Vertices : ";
|
||||
std::cin >> vertices;
|
||||
std::cout << "Enter the Edges : ";
|
||||
std::cin >> edges;
|
||||
|
||||
/// creating a graph
|
||||
std::vector<std::vector<size_t> > adj(vertices, std::vector<size_t>());
|
||||
|
||||
/// taking input for the edges
|
||||
std::cout << "Enter the vertices which have edges between them : " << std::endl;
|
||||
while (edges--) {
|
||||
size_t u = 0, v = 0;
|
||||
std::cin >> u >> v;
|
||||
graph::depth_first_search::addEdge(&adj, u, v);
|
||||
}
|
||||
|
||||
/// taking input for the starting position
|
||||
std::cout << "Enter the starting vertex [1,n]: " << std::endl;
|
||||
std::cin >> start_pos;
|
||||
start_pos -= 1;
|
||||
traversal = graph::depth_first_search::dfs(adj, start_pos);
|
||||
|
||||
/// Printing the order of traversal
|
||||
for (auto x : traversal) {
|
||||
std::cout << x << ' ';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Graph Dijkstras Shortest Path Algorithm
|
||||
* (Dijkstra's Shortest Path)]
|
||||
* (https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
|
||||
*
|
||||
* @author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
*
|
||||
* @details
|
||||
* Dijkstra's Algorithm is used to find the shortest path from a source
|
||||
* vertex to all other reachable vertex in the graph.
|
||||
* The algorithm initially assumes all the nodes are unreachable from the
|
||||
* given source vertex so we mark the distances of all vertices as INF
|
||||
* (infinity) from source vertex (INF / infinity denotes unable to reach).
|
||||
*
|
||||
* in similar fashion with BFS we assume the distance of source vertex as 0
|
||||
* and pushes the vertex in a priority queue with it's distance.
|
||||
* we maintain the priority queue as a min heap so that we can get the
|
||||
* minimum element at the top of heap
|
||||
*
|
||||
* Basically what we do in this algorithm is that we try to minimize the
|
||||
* distances of all the reachable vertices from the current vertex, look
|
||||
* at the code below to understand in better way.
|
||||
*
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
constexpr int64_t INF = std::numeric_limits<int64_t>::max();
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph Algorithms
|
||||
*/
|
||||
|
||||
namespace graph {
|
||||
/**
|
||||
* @brief Function that add edge between two nodes or vertices of graph
|
||||
*
|
||||
* @param u any node or vertex of graph
|
||||
* @param v any node or vertex of graph
|
||||
*/
|
||||
void addEdge(std::vector<std::vector<std::pair<int, int>>> *adj, int u, int v,
|
||||
int w) {
|
||||
(*adj)[u - 1].push_back(std::make_pair(v - 1, w));
|
||||
// (*adj)[v - 1].push_back(std::make_pair(u - 1, w));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function runs the dijkstra algorithm for some source vertex and
|
||||
* target vertex in the graph and returns the shortest distance of target
|
||||
* from the source.
|
||||
*
|
||||
* @param adj input graph
|
||||
* @param s source vertex
|
||||
* @param t target vertex
|
||||
*
|
||||
* @return shortest distance if target is reachable from source else -1 in
|
||||
* case if target is not reachable from source.
|
||||
*/
|
||||
int dijkstra(std::vector<std::vector<std::pair<int, int>>> *adj, int s, int t) {
|
||||
/// n denotes the number of vertices in graph
|
||||
int n = adj->size();
|
||||
|
||||
/// setting all the distances initially to INF
|
||||
std::vector<int64_t> dist(n, INF);
|
||||
|
||||
/// creating a min heap using priority queue
|
||||
/// first element of pair contains the distance
|
||||
/// second element of pair contains the vertex
|
||||
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>,
|
||||
std::greater<std::pair<int, int>>>
|
||||
pq;
|
||||
|
||||
/// pushing the source vertex 's' with 0 distance in min heap
|
||||
pq.push(std::make_pair(0, s));
|
||||
|
||||
/// marking the distance of source as 0
|
||||
dist[s] = 0;
|
||||
|
||||
while (!pq.empty()) {
|
||||
/// second element of pair denotes the node / vertex
|
||||
int currentNode = pq.top().second;
|
||||
|
||||
/// first element of pair denotes the distance
|
||||
int currentDist = pq.top().first;
|
||||
|
||||
pq.pop();
|
||||
|
||||
/// for all the reachable vertex from the currently exploring vertex
|
||||
/// we will try to minimize the distance
|
||||
for (std::pair<int, int> edge : (*adj)[currentNode]) {
|
||||
/// minimizing distances
|
||||
if (currentDist + edge.second < dist[edge.first]) {
|
||||
dist[edge.first] = currentDist + edge.second;
|
||||
pq.push(std::make_pair(dist[edge.first], edge.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dist[t] != INF) {
|
||||
return dist[t];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} // namespace graph
|
||||
|
||||
/** Function to test the Algorithm */
|
||||
void tests() {
|
||||
std::cout << "Initiatinig Predefined Tests..." << std::endl;
|
||||
std::cout << "Initiating Test 1..." << std::endl;
|
||||
std::vector<std::vector<std::pair<int, int>>> adj1(
|
||||
4, std::vector<std::pair<int, int>>());
|
||||
graph::addEdge(&adj1, 1, 2, 1);
|
||||
graph::addEdge(&adj1, 4, 1, 2);
|
||||
graph::addEdge(&adj1, 2, 3, 2);
|
||||
graph::addEdge(&adj1, 1, 3, 5);
|
||||
|
||||
int s = 1, t = 3;
|
||||
assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3);
|
||||
std::cout << "Test 1 Passed..." << std::endl;
|
||||
|
||||
s = 4, t = 3;
|
||||
std::cout << "Initiating Test 2..." << std::endl;
|
||||
assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5);
|
||||
std::cout << "Test 2 Passed..." << std::endl;
|
||||
|
||||
std::vector<std::vector<std::pair<int, int>>> adj2(
|
||||
5, std::vector<std::pair<int, int>>());
|
||||
graph::addEdge(&adj2, 1, 2, 4);
|
||||
graph::addEdge(&adj2, 1, 3, 2);
|
||||
graph::addEdge(&adj2, 2, 3, 2);
|
||||
graph::addEdge(&adj2, 3, 2, 1);
|
||||
graph::addEdge(&adj2, 2, 4, 2);
|
||||
graph::addEdge(&adj2, 3, 5, 4);
|
||||
graph::addEdge(&adj2, 5, 4, 1);
|
||||
graph::addEdge(&adj2, 2, 5, 3);
|
||||
graph::addEdge(&adj2, 3, 4, 4);
|
||||
|
||||
s = 1, t = 5;
|
||||
std::cout << "Initiating Test 3..." << std::endl;
|
||||
assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6);
|
||||
std::cout << "Test 3 Passed..." << std::endl;
|
||||
std::cout << "All Test Passed..." << std::endl << std::endl;
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
// running predefined tests
|
||||
tests();
|
||||
|
||||
int vertices = int(), edges = int();
|
||||
std::cout << "Enter the number of vertices : ";
|
||||
std::cin >> vertices;
|
||||
std::cout << "Enter the number of edges : ";
|
||||
std::cin >> edges;
|
||||
|
||||
std::vector<std::vector<std::pair<int, int>>> adj(
|
||||
vertices, std::vector<std::pair<int, int>>());
|
||||
|
||||
int u = int(), v = int(), w = int();
|
||||
while (edges--) {
|
||||
std::cin >> u >> v >> w;
|
||||
graph::addEdge(&adj, u, v, w);
|
||||
}
|
||||
|
||||
int s = int(), t = int();
|
||||
std::cin >> s >> t;
|
||||
int dist = graph::dijkstra(&adj, s - 1, t - 1);
|
||||
if (dist == -1) {
|
||||
std::cout << "Target not reachable from source" << std::endl;
|
||||
} else {
|
||||
std::cout << "Shortest Path Distance : " << dist << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief The implementation of [Hamilton's
|
||||
* cycle](https://en.wikipedia.org/wiki/Hamiltonian_path) dynamic solution for
|
||||
* vertices number less than 20.
|
||||
* @details
|
||||
* I use \f$2^n\times n\f$ matrix and for every \f$[i, j]\f$ (\f$i < 2^n\f$ and
|
||||
* \f$j < n\f$) in the matrix I store `true` if it is possible to get to all
|
||||
* vertices on which position in `i`'s binary representation is `1` so as
|
||||
* \f$j\f$ would be the last one.
|
||||
*
|
||||
* In the the end if any cell in \f$(2^n - 1)^{\mbox{th}}\f$ row is `true` there
|
||||
* exists hamiltonian cycle.
|
||||
*
|
||||
* @author [vakhokoto](https://github.com/vakhokoto)
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* The function determines if there is a hamilton's cycle in the graph
|
||||
*
|
||||
* @param routes nxn boolean matrix of \f$[i, j]\f$ where \f$[i, j]\f$ is `true`
|
||||
* if there is a road from \f$i\f$ to \f$j\f$
|
||||
* @return `true` if there is Hamiltonian cycle in the graph
|
||||
* @return `false` if there is no Hamiltonian cycle in the graph
|
||||
*/
|
||||
bool hamilton_cycle(const std::vector<std::vector<bool>> &routes) {
|
||||
const size_t n = routes.size();
|
||||
// height of dp array which is 2^n
|
||||
const size_t height = 1 << n;
|
||||
std::vector<std::vector<bool>> dp(height, std::vector<bool>(n, false));
|
||||
|
||||
// to fill in the [2^i, i] cells with true
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
dp[1 << i][i] = true;
|
||||
}
|
||||
for (size_t i = 1; i < height; i++) {
|
||||
std::vector<size_t> zeros, ones;
|
||||
// finding positions with 1s and 0s and separate them
|
||||
for (size_t pos = 0; pos < n; ++pos) {
|
||||
if ((1 << pos) & i) {
|
||||
ones.push_back(pos);
|
||||
} else {
|
||||
zeros.push_back(pos);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &o : ones) {
|
||||
if (!dp[i][o]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &z : zeros) {
|
||||
if (!routes[o][z]) {
|
||||
continue;
|
||||
}
|
||||
dp[i + (1 << z)][z] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_cycle = false;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
is_cycle |= dp[height - 1][i];
|
||||
if (is_cycle) { // if true, all subsequent loop will be true. hence
|
||||
// break
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_cycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* this test is testing if ::hamilton_cycle returns `true` for
|
||||
* graph: `1 -> 2 -> 3 -> 4`
|
||||
* @return None
|
||||
*/
|
||||
static void test1() {
|
||||
std::vector<std::vector<bool>> arr{
|
||||
std::vector<bool>({true, true, false, false}),
|
||||
std::vector<bool>({false, true, true, false}),
|
||||
std::vector<bool>({false, false, true, true}),
|
||||
std::vector<bool>({false, false, false, true})};
|
||||
|
||||
bool ans = hamilton_cycle(arr);
|
||||
std::cout << "Test 1... ";
|
||||
assert(ans);
|
||||
std::cout << "passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* this test is testing if ::hamilton_cycle returns `false` for
|
||||
* \n graph:<pre>
|
||||
* 1 -> 2 -> 3
|
||||
* |
|
||||
* V
|
||||
* 4</pre>
|
||||
* @return None
|
||||
*/
|
||||
static void test2() {
|
||||
std::vector<std::vector<bool>> arr{
|
||||
std::vector<bool>({true, true, false, false}),
|
||||
std::vector<bool>({false, true, true, true}),
|
||||
std::vector<bool>({false, false, true, false}),
|
||||
std::vector<bool>({false, false, false, true})};
|
||||
|
||||
bool ans = hamilton_cycle(arr);
|
||||
|
||||
std::cout << "Test 2... ";
|
||||
assert(!ans); // not a cycle
|
||||
std::cout << "passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* this test is testing if ::hamilton_cycle returns `true` for
|
||||
* clique with 4 vertices
|
||||
* @return None
|
||||
*/
|
||||
static void test3() {
|
||||
std::vector<std::vector<bool>> arr{
|
||||
std::vector<bool>({true, true, true, true}),
|
||||
std::vector<bool>({true, true, true, true}),
|
||||
std::vector<bool>({true, true, true, true}),
|
||||
std::vector<bool>({true, true, true, true})};
|
||||
|
||||
bool ans = hamilton_cycle(arr);
|
||||
|
||||
std::cout << "Test 3... ";
|
||||
assert(ans);
|
||||
std::cout << "passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*
|
||||
*/
|
||||
int main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Hopcroft–Karp](https://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm) algorithm.
|
||||
* @details
|
||||
* The Hopcroft–Karp algorithm is an algorithm that takes as input a bipartite graph
|
||||
* and produces as output a maximum cardinality matching, it runs in O(E√V) time in worst case.
|
||||
*
|
||||
* ### Bipartite graph
|
||||
* A bipartite graph (or bigraph) is a graph whose vertices can be divided into two disjoint
|
||||
* and independent sets U and V such that every edge connects a vertex in U to one in V.
|
||||
* Vertex sets U and V are usually called the parts of the graph.
|
||||
* Equivalently, a bipartite graph is a graph that does not contain any odd-length cycles.
|
||||
*
|
||||
* ### Matching and Not-Matching edges
|
||||
* Given a matching M, edges that are part of matching are called Matching edges and edges that are not part
|
||||
* of M (or connect free nodes) are called Not-Matching edges.
|
||||
*
|
||||
* ### Maximum cardinality matching
|
||||
* Given a bipartite graphs G = ( V = ( X , Y ) , E ) whose partition has the parts X and Y,
|
||||
* with E denoting the edges of the graph, the goal is to find a matching with as many edges as possible.
|
||||
* Equivalently, a matching that covers as many vertices as possible.
|
||||
*
|
||||
* ### Augmenting paths
|
||||
* Given a matching M, an augmenting path is an alternating path that starts from and ends on free vertices.
|
||||
* All single edge paths that start and end with free vertices are augmenting paths.
|
||||
*
|
||||
*
|
||||
* ### Concept
|
||||
* A matching M is not maximum if there exists an augmenting path. It is also true other way,
|
||||
* i.e, a matching is maximum if no augmenting path exists.
|
||||
*
|
||||
*
|
||||
* ### Algorithm
|
||||
* 1) Initialize the Maximal Matching M as empty.
|
||||
* 2) While there exists an Augmenting Path P
|
||||
* Remove matching edges of P from M and add not-matching edges of P to M
|
||||
* (This increases size of M by 1 as P starts and ends with a free vertex
|
||||
* i.e. a node that is not part of matching.)
|
||||
* 3) Return M.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author [Krishna Pal Deora](https://github.com/Krishnapal4050)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
|
||||
/**
|
||||
* @brief Represents Bipartite graph for
|
||||
* Hopcroft Karp implementation
|
||||
*/
|
||||
class HKGraph
|
||||
{
|
||||
int m{}; ///< m is the number of vertices on left side of Bipartite Graph
|
||||
int n{}; ///< n is the number of vertices on right side of Bipartite Graph
|
||||
const int NIL{0};
|
||||
const int INF{INT_MAX};
|
||||
|
||||
std::vector<std::list<int> >adj; ///< adj[u] stores adjacents of left side and 0 is used for dummy vertex
|
||||
|
||||
std::vector<int> pair_u; ///< value of vertex 'u' ranges from 1 to m
|
||||
std::vector<int> pair_v; ///< value of vertex 'v' ranges from 1 to n
|
||||
std::vector<int> dist; ///< dist represents the distance between vertex 'u' and vertex 'v'
|
||||
|
||||
public:
|
||||
HKGraph(); // Default Constructor
|
||||
HKGraph(int m, int n); // Constructor
|
||||
void addEdge(int u, int v); // To add edge
|
||||
|
||||
bool bfs(); // Returns true if there is an augmenting path
|
||||
bool dfs(int u); // Adds augmenting path if there is one beginning with u
|
||||
|
||||
int hopcroftKarpAlgorithm(); // Returns size of maximum matching
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function counts the number of augmenting paths between left and right sides of the Bipartite graph
|
||||
* @returns size of maximum matching
|
||||
*/
|
||||
int HKGraph::hopcroftKarpAlgorithm()
|
||||
{
|
||||
|
||||
// pair_u[u] stores pair of u in matching on left side of Bipartite Graph.
|
||||
// If u doesn't have any pair, then pair_u[u] is NIL
|
||||
pair_u = std::vector<int>(m + 1,NIL);
|
||||
|
||||
// pair_v[v] stores pair of v in matching on right side of Biparite Graph.
|
||||
// If v doesn't have any pair, then pair_u[v] is NIL
|
||||
pair_v = std::vector<int>(n + 1,NIL);
|
||||
|
||||
dist = std::vector<int>(m + 1); // dist[u] stores distance of left side vertices
|
||||
|
||||
int result = 0; // Initialize result
|
||||
|
||||
// Keep updating the result while there is an augmenting path possible.
|
||||
while (bfs())
|
||||
{
|
||||
// Find a free vertex to check for a matching
|
||||
for (int u = 1; u <= m; u++){
|
||||
|
||||
// If current vertex is free and there is
|
||||
// an augmenting path from current vertex
|
||||
// then increment the result
|
||||
if (pair_u[u] == NIL && dfs(u)){
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function checks for the possibility of augmented path availability
|
||||
* @returns `true` if there is an augmenting path available
|
||||
* @returns `false` if there is no augmenting path available
|
||||
*/
|
||||
bool HKGraph::bfs()
|
||||
{
|
||||
std::queue<int> q; // an integer queue for bfs
|
||||
|
||||
// First layer of vertices (set distance as 0)
|
||||
for (int u = 1; u <= m; u++)
|
||||
{
|
||||
// If this is a free vertex, add it to queue
|
||||
if (pair_u[u] == NIL){
|
||||
|
||||
dist[u] = 0; // u is not matched so distance is 0
|
||||
q.push(u);
|
||||
}
|
||||
|
||||
else{
|
||||
dist[u] = INF; // set distance as infinite so that this vertex is considered next time for availibility
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dist[NIL] = INF; // Initialize distance to NIL as infinite
|
||||
|
||||
// q is going to contain vertices of left side only.
|
||||
while (!q.empty())
|
||||
{
|
||||
int u = q.front(); // dequeue a vertex
|
||||
q.pop();
|
||||
|
||||
// If this node is not NIL and can provide a shorter path to NIL then
|
||||
if (dist[u] < dist[NIL])
|
||||
{
|
||||
// Get all the adjacent vertices of the dequeued vertex u
|
||||
std::list<int>::iterator it;
|
||||
for (it = adj[u].begin(); it != adj[u].end(); ++it)
|
||||
{
|
||||
int v = *it;
|
||||
|
||||
// If pair of v is not considered so far i.e. (v, pair_v[v]) is not yet explored edge.
|
||||
if (dist[pair_v[v]] == INF)
|
||||
{
|
||||
dist[pair_v[v]] = dist[u] + 1;
|
||||
q.push(pair_v[v]); // Consider the pair and push it to queue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (dist[NIL] != INF); // If we could come back to NIL using alternating path of distinct vertices then there is an augmenting path available
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This functions checks whether an augmenting path is available exists beginning with free vertex u
|
||||
* @param u represents position of vertex
|
||||
* @returns `true` if there is an augmenting path beginning with free vertex u
|
||||
* @returns `false` if there is no augmenting path beginning with free vertex u
|
||||
*/
|
||||
bool HKGraph::dfs(int u)
|
||||
{
|
||||
if (u != NIL)
|
||||
{
|
||||
std::list<int>::iterator it;
|
||||
for (it = adj[u].begin(); it != adj[u].end(); ++it)
|
||||
{
|
||||
|
||||
int v = *it; // Adjacent vertex of u
|
||||
|
||||
// Follow the distances set by BFS search
|
||||
if (dist[pair_v[v]] == dist[u] + 1)
|
||||
{
|
||||
// If dfs for pair of v also return true then new matching possible, store the matching
|
||||
if (dfs(pair_v[v]) == true)
|
||||
{
|
||||
pair_v[v] = u;
|
||||
pair_u[u] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dist[u] = INF; // If there is no augmenting path beginning with u then set distance to infinite.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default Constructor for initialization
|
||||
*/
|
||||
HKGraph::HKGraph() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor for initialization
|
||||
* @param m is the number of vertices on left side of Bipartite Graph
|
||||
* @param n is the number of vertices on right side of Bipartite Graph
|
||||
*/
|
||||
HKGraph::HKGraph(int m, int n) {
|
||||
this->m = m;
|
||||
this->n = n;
|
||||
adj = std::vector<std::list<int> >(m + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to add edge from u to v
|
||||
* @param u is the position of first vertex
|
||||
* @param v is the position of second vertex
|
||||
*/
|
||||
void HKGraph::addEdge(int u, int v)
|
||||
{
|
||||
adj[u].push_back(v); // Add v to u’s list.
|
||||
}
|
||||
|
||||
} // namespace graph
|
||||
|
||||
using graph::HKGraph;
|
||||
|
||||
/**
|
||||
* Self-test implementation
|
||||
* @returns none
|
||||
*/
|
||||
void tests(){
|
||||
// Sample test case 1
|
||||
int v1a = 3, v1b = 5; // vertices of left side, right side and edges
|
||||
HKGraph g1(v1a, v1b); // execute the algorithm
|
||||
|
||||
g1.addEdge(0,1);
|
||||
g1.addEdge(1,4);
|
||||
|
||||
int expected_res1 = 0; // for the above sample data, this is the expected output
|
||||
int res1 = g1.hopcroftKarpAlgorithm();
|
||||
|
||||
assert(res1 == expected_res1); // assert check to ensure that the algorithm executed correctly for test 1
|
||||
|
||||
// Sample test case 2
|
||||
int v2a = 4, v2b = 4; // vertices of left side, right side and edges
|
||||
HKGraph g2(v2a, v2b); // execute the algorithm
|
||||
|
||||
g2.addEdge(1,1);
|
||||
g2.addEdge(1,3);
|
||||
g2.addEdge(2,3);
|
||||
g2.addEdge(3,4);
|
||||
g2.addEdge(4,3);
|
||||
g2.addEdge(4,2);
|
||||
|
||||
int expected_res2 = 0; // for the above sample data, this is the expected output
|
||||
int res2 = g2.hopcroftKarpAlgorithm();
|
||||
|
||||
assert(res2 == expected_res2); // assert check to ensure that the algorithm executed correctly for test 2
|
||||
|
||||
// Sample test case 3
|
||||
int v3a = 6, v3b = 6; // vertices of left side, right side and edges
|
||||
HKGraph g3(v3a, v3b); // execute the algorithm
|
||||
|
||||
g3.addEdge(0,1);
|
||||
g3.addEdge(1,4);
|
||||
g3.addEdge(1,5);
|
||||
g3.addEdge(5,0);
|
||||
|
||||
int expected_res3 = 0; // for the above sample data, this is the expected output
|
||||
int res3 = g3.hopcroftKarpAlgorithm();
|
||||
|
||||
assert(res3 == expected_res3); // assert check to ensure that the algorithm executed correctly for test 3
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
tests(); // perform self-tests
|
||||
|
||||
int v1 = 0, v2 = 0, e = 0;
|
||||
std::cin >> v1 >> v2 >> e; // vertices of left side, right side and edges
|
||||
HKGraph g(v1, v2);
|
||||
int u = 0, v = 0;
|
||||
for (int i = 0; i < e; ++i)
|
||||
{
|
||||
std::cin >> u >> v;
|
||||
g.addEdge(u, v);
|
||||
}
|
||||
|
||||
int res = g.hopcroftKarpAlgorithm();
|
||||
std::cout << "Maximum matching is " << res <<"\n";
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Algorithm to check whether a graph is
|
||||
* [bipartite](https://en.wikipedia.org/wiki/Bipartite_graph)
|
||||
*
|
||||
* @details
|
||||
* A graph is a collection of nodes also called vertices and these vertices
|
||||
* are connected by edges. A graph is bipartite if its vertices can be
|
||||
* divided into two disjoint and independent sets U and V such that every edge
|
||||
* connects a vertex in U to one in V.
|
||||
*
|
||||
* The algorithm implemented in this file determines whether the given graph
|
||||
* is bipartite or not.
|
||||
*
|
||||
* <pre>
|
||||
* Example - Here is a graph g1 with 5 vertices and is bipartite
|
||||
*
|
||||
* 1 4
|
||||
* / \ / \
|
||||
* 2 3 5
|
||||
*
|
||||
* Example - Here is a graph G2 with 3 vertices and is not bipartite
|
||||
*
|
||||
* 1 --- 2
|
||||
* \ /
|
||||
* 3
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author [Akshat Vaya](https://github.com/AkVaya)
|
||||
*
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @namespace is_graph_bipartite
|
||||
* @brief Functions for checking whether a graph is bipartite or not
|
||||
*/
|
||||
namespace is_graph_bipartite {
|
||||
/**
|
||||
* @brief Class for representing graph as an adjacency list.
|
||||
*/
|
||||
class Graph {
|
||||
private:
|
||||
int n; ///< size of the graph
|
||||
|
||||
std::vector<std::vector<int> >
|
||||
adj; ///< adj stores the graph as an adjacency list
|
||||
|
||||
std::vector<int> side; ///< stores the side of the vertex
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor that initializes the graph on creation
|
||||
* @param size number of vertices of the graph
|
||||
*/
|
||||
explicit Graph(int size) {
|
||||
n = size;
|
||||
adj.resize(n);
|
||||
side.resize(n, -1);
|
||||
}
|
||||
|
||||
void addEdge(int u, int v); /// function to add edges to our graph
|
||||
|
||||
bool
|
||||
is_bipartite(); /// function to check whether the graph is bipartite or not
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function that add an edge between two nodes or vertices of graph
|
||||
*
|
||||
* @param u is a node or vertex of graph
|
||||
* @param v is a node or vertex of graph
|
||||
*/
|
||||
void Graph::addEdge(int u, int v) {
|
||||
adj[u - 1].push_back(v - 1);
|
||||
adj[v - 1].push_back(u - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function that checks whether the graph is bipartite or not
|
||||
* the function returns true if the graph is a bipartite graph
|
||||
* the function returns false if the graph is not a bipartite graph
|
||||
*
|
||||
* @details
|
||||
* Here, side refers to the two disjoint subsets of the bipartite graph.
|
||||
* Initially, the values of side are set to -1 which is an unassigned state. A
|
||||
* for loop is run for every vertex of the graph. If the current edge has no
|
||||
* side assigned to it, then a Breadth First Search operation is performed. If
|
||||
* two neighbours have the same side then the graph will not be bipartite and
|
||||
* the value of check becomes false. If and only if each pair of neighbours have
|
||||
* different sides, the value of check will be true and hence the graph
|
||||
* bipartite.
|
||||
*
|
||||
* @returns `true` if th graph is bipartite
|
||||
* @returns `false` otherwise
|
||||
*/
|
||||
bool Graph::is_bipartite() {
|
||||
bool check = true;
|
||||
std::queue<int> q;
|
||||
for (int current_edge = 0; current_edge < n; ++current_edge) {
|
||||
if (side[current_edge] == -1) {
|
||||
q.push(current_edge);
|
||||
side[current_edge] = 0;
|
||||
while (q.size()) {
|
||||
int current = q.front();
|
||||
q.pop();
|
||||
for (auto neighbour : adj[current]) {
|
||||
if (side[neighbour] == -1) {
|
||||
side[neighbour] = (1 ^ side[current]);
|
||||
q.push(neighbour);
|
||||
} else {
|
||||
check &= (side[neighbour] != side[current]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return check;
|
||||
}
|
||||
} // namespace is_graph_bipartite
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* Function to test the above algorithm
|
||||
* @returns none
|
||||
*/
|
||||
static void test() {
|
||||
graph::is_graph_bipartite::Graph G1(
|
||||
5); /// creating graph G1 with 5 vertices
|
||||
/// adding edges to the graphs as per the illustrated example
|
||||
G1.addEdge(1, 2);
|
||||
G1.addEdge(1, 3);
|
||||
G1.addEdge(3, 4);
|
||||
G1.addEdge(4, 5);
|
||||
|
||||
graph::is_graph_bipartite::Graph G2(
|
||||
3); /// creating graph G2 with 3 vertices
|
||||
/// adding edges to the graphs as per the illustrated example
|
||||
G2.addEdge(1, 2);
|
||||
G2.addEdge(1, 3);
|
||||
G2.addEdge(2, 3);
|
||||
|
||||
/// checking whether the graphs are bipartite or not
|
||||
if (G1.is_bipartite()) {
|
||||
std::cout << "The given graph G1 is a bipartite graph\n";
|
||||
} else {
|
||||
std::cout << "The given graph G1 is not a bipartite graph\n";
|
||||
}
|
||||
if (G2.is_bipartite()) {
|
||||
std::cout << "The given graph G2 is a bipartite graph\n";
|
||||
} else {
|
||||
std::cout << "The given graph G2 is not a bipartite graph\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
int main() {
|
||||
test(); /// Testing
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @brief Check whether a given graph is bipartite or not
|
||||
* @details
|
||||
* A bipartite graph is the one whose nodes can be divided into two
|
||||
* disjoint sets in such a way that the nodes in a set are not
|
||||
* connected to each other at all, i.e. no intra-set connections.
|
||||
* The only connections that exist are that of inter-set,
|
||||
* i.e. the nodes from one set are connected to a subset of nodes
|
||||
* in the other set.
|
||||
* In this implementation, using a graph in the form of adjacency
|
||||
* list, check whether the given graph is a bipartite or not.
|
||||
*
|
||||
* References used:
|
||||
* [GeeksForGeeks](https://www.geeksforgeeks.org/bipartite-graph/)
|
||||
* @author [tushar2407](https://github.com/tushar2407)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for queue data structure
|
||||
#include <vector> /// for vector data structure
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graphical algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @brief function to check whether the passed graph is bipartite or not
|
||||
* @param graph is a 2D matrix whose rows or the first index signify the node
|
||||
* and values in that row signify the nodes it is connected to
|
||||
* @param index is the valus of the node currently under observation
|
||||
* @param visited is the vector which stores whether a given node has been
|
||||
* traversed or not yet
|
||||
* @returns boolean
|
||||
*/
|
||||
bool checkBipartite(const std::vector<std::vector<int64_t>> &graph,
|
||||
int64_t index, std::vector<int64_t> *visited) {
|
||||
std::queue<int64_t> q; ///< stores the neighbouring node indexes in squence
|
||||
/// of being reached
|
||||
q.push(index); /// insert the current node into the queue
|
||||
(*visited)[index] = 1; /// mark the current node as travelled
|
||||
while (q.size()) {
|
||||
int64_t u = q.front();
|
||||
q.pop();
|
||||
for (uint64_t i = 0; i < graph[u].size(); i++) {
|
||||
int64_t v =
|
||||
graph[u][i]; ///< stores the neighbour of the current node
|
||||
if (!(*visited)[v]) /// check whether the neighbour node is
|
||||
/// travelled already or not
|
||||
{
|
||||
(*visited)[v] =
|
||||
((*visited)[u] == 1)
|
||||
? -1
|
||||
: 1; /// colour the neighbouring node with
|
||||
/// different colour than the current node
|
||||
q.push(v); /// insert the neighbouring node into the queue
|
||||
} else if ((*visited)[v] ==
|
||||
(*visited)[u]) /// if both the current node and its
|
||||
/// neighbour has the same state then it
|
||||
/// is not a bipartite graph
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; /// return true when all the connected nodes of the current
|
||||
/// nodes are travelled and satisify all the above conditions
|
||||
}
|
||||
/**
|
||||
* @brief returns true if the given graph is bipartite else returns false
|
||||
* @param graph is a 2D matrix whose rows or the first index signify the node
|
||||
* and values in that row signify the nodes it is connected to
|
||||
* @returns booleans
|
||||
*/
|
||||
bool isBipartite(const std::vector<std::vector<int64_t>> &graph) {
|
||||
std::vector<int64_t> visited(
|
||||
graph.size()); ///< stores boolean values
|
||||
/// which signify whether that node had been visited or
|
||||
/// not
|
||||
|
||||
for (uint64_t i = 0; i < graph.size(); i++) {
|
||||
if (!visited[i]) /// if the current node is not visited then check
|
||||
/// whether the sub-graph of that node is a bipartite
|
||||
/// or not
|
||||
{
|
||||
if (!checkBipartite(graph, i, &visited)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<std::vector<int64_t>> graph = {{1, 3}, {0, 2}, {1, 3}, {0, 2}};
|
||||
|
||||
assert(graph::isBipartite(graph) ==
|
||||
true); /// check whether the above
|
||||
/// defined graph is indeed bipartite
|
||||
|
||||
std::vector<std::vector<int64_t>> graph_not_bipartite = {
|
||||
{1, 2, 3}, {0, 2}, {0, 1, 3}, {0, 2}};
|
||||
|
||||
assert(graph::isBipartite(graph_not_bipartite) ==
|
||||
false); /// check whether
|
||||
/// the above defined graph is indeed bipartite
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* Instantitates a dummy graph of a small size with
|
||||
* a few edges between random nodes.
|
||||
* On applying the algorithm, it checks if the instantiated
|
||||
* graph is bipartite or not.
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/* Implementation of Kosaraju's Algorithm to find out the strongly connected
|
||||
components (SCCs) in a graph. Author:Anirban166
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Iterative function/method to print graph:
|
||||
* @param a adjacency list representation of the graph
|
||||
* @param V number of vertices
|
||||
* @return void
|
||||
**/
|
||||
void print(const std::vector<std::vector<int> > &a, int V) {
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (!a[i].empty()) {
|
||||
std::cout << "i=" << i << "-->";
|
||||
}
|
||||
for (int j : a[i]) {
|
||||
std::cout << j << " ";
|
||||
}
|
||||
if (!a[i].empty()) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* //Recursive function/method to push vertices into stack passed as parameter:
|
||||
* @param v vertices
|
||||
* @param st stack passed by reference
|
||||
* @param vis array to keep track of visited nodes (boolean type)
|
||||
* @param adj adjacency list representation of the graph
|
||||
* @return void
|
||||
**/
|
||||
void push_vertex(int v, std::stack<int> *st, std::vector<bool> *vis,
|
||||
const std::vector<std::vector<int> > &adj) {
|
||||
(*vis)[v] = true;
|
||||
for (auto i = adj[v].begin(); i != adj[v].end(); i++) {
|
||||
if ((*vis)[*i] == false) {
|
||||
push_vertex(*i, st, vis, adj);
|
||||
}
|
||||
}
|
||||
st->push(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* //Recursive function/method to implement depth first traversal(dfs):
|
||||
* @param v vertices
|
||||
* @param vis array to keep track of visited nodes (boolean type)
|
||||
* @param grev graph with reversed edges
|
||||
* @return void
|
||||
**/
|
||||
void dfs(int v, std::vector<bool> *vis,
|
||||
const std::vector<std::vector<int> > &grev) {
|
||||
(*vis)[v] = true;
|
||||
// cout<<v<<" ";
|
||||
for (auto i = grev[v].begin(); i != grev[v].end(); i++) {
|
||||
if ((*vis)[*i] == false) {
|
||||
dfs(*i, vis, grev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// function/method to implement Kosaraju's Algorithm:
|
||||
/**
|
||||
* Info about the method
|
||||
* @param V vertices in graph
|
||||
* @param adj array of vectors that represent a graph (adjacency list/array)
|
||||
* @return int ( 0, 1, 2..and so on, only unsigned values as either there can be
|
||||
no SCCs i.e. none(0) or there will be x no. of SCCs (x>0)) i.e. it returns the
|
||||
count of (number of) strongly connected components (SCCs) in the graph.
|
||||
(variable 'count_scc' within function)
|
||||
**/
|
||||
int kosaraju(int V, const std::vector<std::vector<int> > &adj) {
|
||||
std::vector<bool> vis(V, false);
|
||||
std::stack<int> st;
|
||||
for (int v = 0; v < V; v++) {
|
||||
if (vis[v] == false) {
|
||||
push_vertex(v, &st, &vis, adj);
|
||||
}
|
||||
}
|
||||
// making new graph (grev) with reverse edges as in adj[]:
|
||||
std::vector<std::vector<int> > grev(V);
|
||||
for (int i = 0; i < V + 1; i++) {
|
||||
for (auto j = adj[i].begin(); j != adj[i].end(); j++) {
|
||||
grev[*j].push_back(i);
|
||||
}
|
||||
}
|
||||
// cout<<"grev="<<endl; ->debug statement
|
||||
// print(grev,V); ->debug statement
|
||||
// reinitialise visited to 0
|
||||
for (int i = 0; i < V; i++) vis[i] = false;
|
||||
int count_scc = 0;
|
||||
while (!st.empty()) {
|
||||
int t = st.top();
|
||||
st.pop();
|
||||
if (vis[t] == false) {
|
||||
dfs(t, &vis, grev);
|
||||
count_scc++;
|
||||
}
|
||||
}
|
||||
// cout<<"count_scc="<<count_scc<<endl; //in case you want to print here
|
||||
// itself, uncomment & change return type of function to void.
|
||||
return count_scc;
|
||||
}
|
||||
|
||||
// All critical/corner cases have been taken care of.
|
||||
// Input your required values: (not hardcoded)
|
||||
int main() {
|
||||
int t = 0;
|
||||
std::cin >> t;
|
||||
while (t--) {
|
||||
int a = 0, b = 0; // a->number of nodes, b->directed edges.
|
||||
std::cin >> a >> b;
|
||||
int m = 0, n = 0;
|
||||
std::vector<std::vector<int> > adj(a + 1);
|
||||
for (int i = 0; i < b; i++) // take total b inputs of 2 vertices each
|
||||
// required to form an edge.
|
||||
{
|
||||
std::cin >> m >> n; // take input m,n denoting edge from m->n.
|
||||
adj[m].push_back(n);
|
||||
}
|
||||
// pass number of nodes and adjacency array as parameters to function:
|
||||
std::cout << kosaraju(a, adj) << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
//#include <boost/multiprecision/cpp_int.hpp>
|
||||
// using namespace boost::multiprecision;
|
||||
const int mx = 1e6 + 5;
|
||||
using ll = int64_t;
|
||||
|
||||
std::array<ll, mx> parent;
|
||||
ll node, edge;
|
||||
std::vector<std::pair<ll, std::pair<ll, ll>>> edges;
|
||||
void initial() {
|
||||
for (int i = 0; i < node + edge; ++i) {
|
||||
parent[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int root(int i) {
|
||||
while (parent[i] != i) {
|
||||
parent[i] = parent[parent[i]];
|
||||
i = parent[i];
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void join(int x, int y) {
|
||||
int root_x = root(x); // Disjoint set union by rank
|
||||
int root_y = root(y);
|
||||
parent[root_x] = root_y;
|
||||
}
|
||||
|
||||
ll kruskal() {
|
||||
ll mincost = 0;
|
||||
for (int i = 0; i < edge; ++i) {
|
||||
ll x = edges[i].second.first;
|
||||
ll y = edges[i].second.second;
|
||||
if (root(x) != root(y)) {
|
||||
mincost += edges[i].first;
|
||||
join(x, y);
|
||||
}
|
||||
}
|
||||
return mincost;
|
||||
}
|
||||
|
||||
int main() {
|
||||
while (true) {
|
||||
int from = 0, to = 0, cost = 0, totalcost = 0;
|
||||
std::cin >> node >> edge; // Enter the nodes and edges
|
||||
if (node == 0 && edge == 0) {
|
||||
break; // Enter 0 0 to break out
|
||||
}
|
||||
initial(); // Initialise the parent array
|
||||
for (int i = 0; i < edge; ++i) {
|
||||
std::cin >> from >> to >> cost;
|
||||
edges.emplace_back(make_pair(cost, std::make_pair(from, to)));
|
||||
totalcost += cost;
|
||||
}
|
||||
sort(edges.begin(), edges.end());
|
||||
std::cout << kruskal() << std::endl;
|
||||
edges.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
*
|
||||
* \brief Data structure for finding the lowest common ancestor
|
||||
* of two vertices in a rooted tree using binary lifting.
|
||||
*
|
||||
* \details
|
||||
* Algorithm: https://cp-algorithms.com/graph/lca_binary_lifting.html
|
||||
*
|
||||
* Complexity:
|
||||
* - Precomputation: \f$O(N \log N)\f$ where \f$N\f$ is the number of vertices
|
||||
* in the tree
|
||||
* - Query: \f$O(\log N)\f$
|
||||
* - Space: \f$O(N \log N)\f$
|
||||
*
|
||||
* Example:
|
||||
* <br/> Tree:
|
||||
* <pre>
|
||||
* _ 3 _
|
||||
* / | \
|
||||
* 1 6 4
|
||||
* / | / \ \
|
||||
* 7 5 2 8 0
|
||||
* |
|
||||
* 9
|
||||
* </pre>
|
||||
*
|
||||
* <br/> lowest_common_ancestor(7, 4) = 3
|
||||
* <br/> lowest_common_ancestor(9, 6) = 6
|
||||
* <br/> lowest_common_ancestor(0, 0) = 0
|
||||
* <br/> lowest_common_ancestor(8, 2) = 6
|
||||
*
|
||||
* The query is symmetrical, therefore
|
||||
* lowest_common_ancestor(x, y) = lowest_common_ancestor(y, x)
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \namespace graph
|
||||
* \brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* Class for representing a graph as an adjacency list.
|
||||
* Its vertices are indexed 0, 1, ..., N - 1.
|
||||
*/
|
||||
class Graph {
|
||||
public:
|
||||
/**
|
||||
* \brief Populate the adjacency list for each vertex in the graph.
|
||||
* Assumes that evey edge is a pair of valid vertex indices.
|
||||
*
|
||||
* @param N number of vertices in the graph
|
||||
* @param undirected_edges list of graph's undirected edges
|
||||
*/
|
||||
Graph(size_t N, const std::vector<std::pair<int, int> > &undirected_edges) {
|
||||
neighbors.resize(N);
|
||||
for (auto &edge : undirected_edges) {
|
||||
neighbors[edge.first].push_back(edge.second);
|
||||
neighbors[edge.second].push_back(edge.first);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the number of vertices in the graph
|
||||
* @return the number of vertices in the graph.
|
||||
*/
|
||||
int number_of_vertices() const { return neighbors.size(); }
|
||||
|
||||
/** \brief for each vertex it stores a list indicies of its neighbors */
|
||||
std::vector<std::vector<int> > neighbors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Representation of a rooted tree. For every vertex its parent is
|
||||
* precalculated.
|
||||
*/
|
||||
class RootedTree : public Graph {
|
||||
public:
|
||||
/**
|
||||
* \brief Constructs the tree by calculating parent for every vertex.
|
||||
* Assumes a valid description of a tree is provided.
|
||||
*
|
||||
* @param undirected_edges list of graph's undirected edges
|
||||
* @param root_ index of the root vertex
|
||||
*/
|
||||
RootedTree(const std::vector<std::pair<int, int> > &undirected_edges,
|
||||
int root_)
|
||||
: Graph(undirected_edges.size() + 1, undirected_edges), root(root_) {
|
||||
populate_parents();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Stores parent of every vertex and for root its own index.
|
||||
* The root is technically not its own parent, but it's very practical
|
||||
* for the lowest common ancestor algorithm.
|
||||
*/
|
||||
std::vector<int> parent;
|
||||
/** \brief Stores the distance from the root. */
|
||||
std::vector<int> level;
|
||||
/** \brief Index of the root vertex. */
|
||||
int root;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Calculate the parents for all the vertices in the tree.
|
||||
* Implements the breadth first search algorithm starting from the root
|
||||
* vertex searching the entire tree and labeling parents for all vertices.
|
||||
* @returns none
|
||||
*/
|
||||
void populate_parents() {
|
||||
// Initialize the vector with -1 which indicates the vertex
|
||||
// wasn't yet visited.
|
||||
parent = std::vector<int>(number_of_vertices(), -1);
|
||||
level = std::vector<int>(number_of_vertices());
|
||||
parent[root] = root;
|
||||
level[root] = 0;
|
||||
std::queue<int> queue_of_vertices;
|
||||
queue_of_vertices.push(root);
|
||||
while (!queue_of_vertices.empty()) {
|
||||
int vertex = queue_of_vertices.front();
|
||||
queue_of_vertices.pop();
|
||||
for (int neighbor : neighbors[vertex]) {
|
||||
// As long as the vertex was not yet visited.
|
||||
if (parent[neighbor] == -1) {
|
||||
parent[neighbor] = vertex;
|
||||
level[neighbor] = level[vertex] + 1;
|
||||
queue_of_vertices.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure that holds a rooted tree and allow for effecient
|
||||
* queries of the lowest common ancestor of two given vertices in the tree.
|
||||
*/
|
||||
class LowestCommonAncestor {
|
||||
public:
|
||||
/**
|
||||
* \brief Stores the tree and precomputs "up lifts".
|
||||
* @param tree_ rooted tree.
|
||||
*/
|
||||
explicit LowestCommonAncestor(const RootedTree &tree_) : tree(tree_) {
|
||||
populate_up();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Query the structure to find the lowest common ancestor.
|
||||
* Assumes that the provided numbers are valid indices of vertices.
|
||||
* Iterativelly modifies ("lifts") u an v until it finnds their lowest
|
||||
* common ancestor.
|
||||
* @param u index of one of the queried vertex
|
||||
* @param v index of the other queried vertex
|
||||
* @return index of the vertex which is the lowet common ancestor of u and v
|
||||
*/
|
||||
int lowest_common_ancestor(int u, int v) const {
|
||||
// Ensure u is the deeper (higher level) of the two vertices
|
||||
if (tree.level[v] > tree.level[u]) {
|
||||
std::swap(u, v);
|
||||
}
|
||||
|
||||
// "Lift" u to the same level as v.
|
||||
int level_diff = tree.level[u] - tree.level[v];
|
||||
for (int i = 0; (1 << i) <= level_diff; ++i) {
|
||||
if (level_diff & (1 << i)) {
|
||||
u = up[u][i];
|
||||
}
|
||||
}
|
||||
assert(tree.level[u] == tree.level[v]);
|
||||
|
||||
if (u == v) {
|
||||
return u;
|
||||
}
|
||||
|
||||
// "Lift" u and v to their 2^i th ancestor if they are different
|
||||
for (int i = static_cast<int>(up[u].size()) - 1; i >= 0; --i) {
|
||||
if (up[u][i] != up[v][i]) {
|
||||
u = up[u][i];
|
||||
v = up[v][i];
|
||||
}
|
||||
}
|
||||
|
||||
// As we regressed u an v such that they cannot further be lifted so
|
||||
// that their ancestor would be different, the only logical
|
||||
// consequence is that their parent is the sought answer.
|
||||
assert(up[u][0] == up[v][0]);
|
||||
return up[u][0];
|
||||
}
|
||||
|
||||
/* \brief reference to the rooted tree this structure allows to query */
|
||||
const RootedTree &tree;
|
||||
/**
|
||||
* \brief for every vertex stores a list of its ancestors by powers of two
|
||||
* For each vertex, the first element of the corresponding list contains
|
||||
* the index of its parent. The i-th element of the list is an index of
|
||||
* the (2^i)-th ancestor of the vertex.
|
||||
*/
|
||||
std::vector<std::vector<int> > up;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Populate the "up" structure. See above.
|
||||
*/
|
||||
void populate_up() {
|
||||
up.resize(tree.number_of_vertices());
|
||||
for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) {
|
||||
up[vertex].push_back(tree.parent[vertex]);
|
||||
}
|
||||
for (int level = 0; (1 << level) < tree.number_of_vertices(); ++level) {
|
||||
for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) {
|
||||
// up[vertex][level + 1] = 2^(level + 1) th ancestor of vertex =
|
||||
// = 2^level th ancestor of 2^level th ancestor of vertex =
|
||||
// = 2^level th ancestor of up[vertex][level]
|
||||
up[vertex].push_back(up[up[vertex][level]][level]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* Unit tests
|
||||
* @returns none
|
||||
*/
|
||||
static void tests() {
|
||||
/**
|
||||
* _ 3 _
|
||||
* / | \
|
||||
* 1 6 4
|
||||
* / | / \ \
|
||||
* 7 5 2 8 0
|
||||
* |
|
||||
* 9
|
||||
*/
|
||||
std::vector<std::pair<int, int> > edges = {
|
||||
{7, 1}, {1, 5}, {1, 3}, {3, 6}, {6, 2}, {2, 9}, {6, 8}, {4, 3}, {0, 4}};
|
||||
graph::RootedTree t(edges, 3);
|
||||
graph::LowestCommonAncestor lca(t);
|
||||
assert(lca.lowest_common_ancestor(7, 4) == 3);
|
||||
assert(lca.lowest_common_ancestor(9, 6) == 6);
|
||||
assert(lca.lowest_common_ancestor(0, 0) == 0);
|
||||
assert(lca.lowest_common_ancestor(8, 2) == 6);
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
tests();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Author: Amit Kumar
|
||||
* Created: May 24, 2020
|
||||
* Copyright: 2020, Open-Source
|
||||
* Last Modified: May 25, 2020
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
// std::max capacity of node in graph
|
||||
const int MAXN = 505;
|
||||
class Graph {
|
||||
std::vector<std::vector<int> > residual_capacity, capacity;
|
||||
int total_nodes = 0;
|
||||
int total_edges = 0, source = 0, sink = 0;
|
||||
std::vector<int> parent;
|
||||
std::vector<std::tuple<int, int, int> > edge_participated;
|
||||
std::bitset<MAXN> visited;
|
||||
int max_flow = 0;
|
||||
bool bfs(int source, int sink) { // to find the augmented - path
|
||||
visited.reset();
|
||||
std::queue<int> q;
|
||||
q.push(source);
|
||||
while (q.empty() == false) {
|
||||
int current_node = q.front();
|
||||
visited.set(current_node);
|
||||
q.pop();
|
||||
for (int i = 0; i < total_nodes; ++i) {
|
||||
if (residual_capacity[current_node][i] > 0 && !visited[i]) {
|
||||
visited.set(i);
|
||||
parent[i] = current_node;
|
||||
if (i == sink) {
|
||||
return true;
|
||||
}
|
||||
q.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
void set_graph() {
|
||||
std::cin >> total_nodes >> total_edges >> source >> sink;
|
||||
parent = std::vector<int>(total_nodes, -1);
|
||||
capacity = residual_capacity = std::vector<std::vector<int> >(
|
||||
total_nodes, std::vector<int>(total_nodes));
|
||||
for (int start = 0, destination = 0, capacity_ = 0, i = 0;
|
||||
i < total_edges; ++i) {
|
||||
std::cin >> start >> destination >> capacity_;
|
||||
residual_capacity[start][destination] = capacity_;
|
||||
capacity[start][destination] = capacity_;
|
||||
}
|
||||
}
|
||||
void ford_fulkerson() {
|
||||
while (bfs(source, sink)) {
|
||||
int current_node = sink;
|
||||
int flow = std::numeric_limits<int>::max();
|
||||
while (current_node != source) {
|
||||
int parent_ = parent[current_node];
|
||||
flow = std::min(flow, residual_capacity[parent_][current_node]);
|
||||
current_node = parent_;
|
||||
}
|
||||
current_node = sink;
|
||||
max_flow += flow;
|
||||
while (current_node != source) {
|
||||
int parent_ = parent[current_node];
|
||||
residual_capacity[parent_][current_node] -= flow;
|
||||
residual_capacity[current_node][parent_] += flow;
|
||||
current_node = parent_;
|
||||
}
|
||||
}
|
||||
}
|
||||
void print_flow_info() {
|
||||
for (int i = 0; i < total_nodes; ++i) {
|
||||
for (int j = 0; j < total_nodes; ++j) {
|
||||
if (capacity[i][j] &&
|
||||
residual_capacity[i][j] < capacity[i][j]) {
|
||||
edge_participated.emplace_back(std::make_tuple(
|
||||
i, j, capacity[i][j] - residual_capacity[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "\nNodes : " << total_nodes << "\nMax flow: " << max_flow
|
||||
<< "\nEdge present in flow: " << edge_participated.size()
|
||||
<< '\n';
|
||||
std::cout << "\nSource\tDestination\tCapacity\total_nodes";
|
||||
for (auto& edge_data : edge_participated) {
|
||||
int source = 0, destination = 0, capacity_ = 0;
|
||||
std::tie(source, destination, capacity_) = edge_data;
|
||||
std::cout << source << "\t" << destination << "\t\t" << capacity_
|
||||
<< '\t';
|
||||
}
|
||||
}
|
||||
};
|
||||
int main() {
|
||||
/*
|
||||
Input Graph: (for testing )
|
||||
4 5 0 3
|
||||
0 1 10
|
||||
1 2 1
|
||||
1 3 1
|
||||
0 2 1
|
||||
2 3 10
|
||||
*/
|
||||
Graph graph;
|
||||
graph.set_graph();
|
||||
graph.ford_fulkerson();
|
||||
graph.print_flow_info();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Algorithm to count paths between two nodes in a directed graph using DFS
|
||||
* @details
|
||||
* This algorithm implements Depth First Search (DFS) to count the number of
|
||||
* possible paths between two nodes in a directed graph. It is represented using
|
||||
* an adjacency matrix. The algorithm recursively traverses the graph to find
|
||||
* all paths from the source node `u` to the destination node `v`.
|
||||
*
|
||||
* @author [Aditya Borate](https://github.com/adi776borate)
|
||||
* @see https://en.wikipedia.org/wiki/Path_(graph_theory)
|
||||
*/
|
||||
|
||||
#include <vector> /// for std::vector
|
||||
#include <iostream> /// for IO operations
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for fixed-size integer types (e.g., std::uint32_t)
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
|
||||
/**
|
||||
* @brief Helper function to perform DFS and count the number of paths from node `u` to node `v`
|
||||
* @param A adjacency matrix representing the graph (1: edge exists, 0: no edge)
|
||||
* @param u the starting node
|
||||
* @param v the destination node
|
||||
* @param n the number of nodes in the graph
|
||||
* @param visited a vector to keep track of visited nodes in the current DFS path
|
||||
* @returns the number of paths from node `u` to node `v`
|
||||
*/
|
||||
std::uint32_t count_paths_dfs(const std::vector<std::vector<std::uint32_t>>& A,
|
||||
std::uint32_t u,
|
||||
std::uint32_t v,
|
||||
std::uint32_t n,
|
||||
std::vector<bool>& visited) {
|
||||
if (u == v) {
|
||||
return 1; // Base case: Reached the destination node
|
||||
}
|
||||
|
||||
visited[u] = true; // Mark the current node as visited
|
||||
std::uint32_t path_count = 0; // Count of all paths from `u` to `v`
|
||||
|
||||
for (std::uint32_t i = 0; i < n; i++) {
|
||||
if (A[u][i] == 1 && !visited[i]) { // Check if there is an edge and the node is not visited
|
||||
path_count += count_paths_dfs(A, i, v, n, visited); // Recursively explore paths from `i` to `v`
|
||||
}
|
||||
}
|
||||
|
||||
visited[u] = false; // Unmark the current node as visited (backtracking)
|
||||
return path_count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Counts the number of paths from node `u` to node `v` in a directed graph
|
||||
* using Depth First Search (DFS)
|
||||
*
|
||||
* @param A adjacency matrix representing the graph (1: edge exists, 0: no edge)
|
||||
* @param u the starting node
|
||||
* @param v the destination node
|
||||
* @param n the number of nodes in the graph
|
||||
* @returns the number of paths from node `u` to node `v`
|
||||
*/
|
||||
std::uint32_t count_paths(const std::vector<std::vector<std::uint32_t>>& A,
|
||||
std::uint32_t u,
|
||||
std::uint32_t v,
|
||||
std::uint32_t n) {
|
||||
// Check for invalid nodes or empty graph
|
||||
if (u >= n || v >= n || A.empty() || A[0].empty()) {
|
||||
return 0; // No valid paths if graph is empty or nodes are out of bounds
|
||||
}
|
||||
|
||||
std::vector<bool> visited(n, false); // Initialize a visited vector for tracking nodes
|
||||
return count_paths_dfs(A, u, v, n, visited); // Start DFS
|
||||
}
|
||||
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test case 1: Simple directed graph with multiple paths
|
||||
std::vector<std::vector<std::uint32_t>> graph1 = {
|
||||
{0, 1, 0, 1, 0},
|
||||
{0, 0, 1, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
std::uint32_t n1 = 5, u1 = 0, v1 = 4;
|
||||
assert(graph::count_paths(graph1, u1, v1, n1) == 3); // There are 3 paths from node 0 to 4
|
||||
|
||||
// Test case 2: No possible path (disconnected graph)
|
||||
std::vector<std::vector<std::uint32_t>> graph2 = {
|
||||
{0, 1, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
std::uint32_t n2 = 5, u2 = 0, v2 = 4;
|
||||
assert(graph::count_paths(graph2, u2, v2, n2) == 0); // No path from node 0 to 4
|
||||
|
||||
// Test case 3: Cyclic graph with multiple paths
|
||||
std::vector<std::vector<std::uint32_t>> graph3 = {
|
||||
{0, 1, 0, 0, 0},
|
||||
{0, 0, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 0, 1, 0, 1},
|
||||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
std::uint32_t n3 = 5, u3 = 0, v3 = 4;
|
||||
assert(graph::count_paths(graph3, u3, v3, n3) == 3); // There are 3 paths from node 0 to 4
|
||||
|
||||
// Test case 4: Single node graph (self-loop)
|
||||
std::vector<std::vector<std::uint32_t>> graph4 = {
|
||||
{0}
|
||||
};
|
||||
std::uint32_t n4 = 1, u4 = 0, v4 = 0;
|
||||
assert(graph::count_paths(graph4, u4, v4, n4) == 1); // There is self-loop, so 1 path from node 0 to 0
|
||||
|
||||
// Test case 5: Empty graph (no nodes, no paths)
|
||||
std::vector<std::vector<std::uint32_t>> graph5 = {{}};
|
||||
int n5 = 0, u5 = 0, v5 = 0;
|
||||
assert(graph::count_paths(graph5, u5, v5, n5) == 0); // There are no paths in an empty graph
|
||||
|
||||
// Test case 6: Invalid nodes (out of bounds)
|
||||
std::vector<std::vector<std::uint32_t>> graph6 = {
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
int n6 = 3, u6 = 0, v6 = 5; // Node `v` is out of bounds (n = 3, so valid indices are 0, 1, 2)
|
||||
assert(graph::count_paths(graph6, u6, v6, n6) == 0); // Should return 0 because `v = 5` is invalid
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // Run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// C++ program to implement Prim's Algorithm
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
using PII = std::pair<int, int>;
|
||||
|
||||
int prim(int x, const std::vector<std::vector<PII> > &graph) {
|
||||
// priority queue to maintain edges with respect to weights
|
||||
std::priority_queue<PII, std::vector<PII>, std::greater<PII> > Q;
|
||||
std::vector<bool> marked(graph.size(), false);
|
||||
int minimum_cost = 0;
|
||||
|
||||
Q.push(std::make_pair(0, x));
|
||||
while (!Q.empty()) {
|
||||
// Select the edge with minimum weight
|
||||
PII p = Q.top();
|
||||
Q.pop();
|
||||
x = p.second;
|
||||
// Checking for cycle
|
||||
if (marked[x] == true) {
|
||||
continue;
|
||||
}
|
||||
minimum_cost += p.first;
|
||||
marked[x] = true;
|
||||
for (const PII &neighbor : graph[x]) {
|
||||
int y = neighbor.second;
|
||||
if (marked[y] == false) {
|
||||
Q.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return minimum_cost;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int nodes = 0, edges = 0;
|
||||
std::cin >> nodes >> edges; // number of nodes & edges in graph
|
||||
if (nodes == 0 || edges == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::vector<PII> > graph(nodes);
|
||||
|
||||
// Edges with their nodes & weight
|
||||
for (int i = 0; i < edges; ++i) {
|
||||
int x = 0, y = 0, weight = 0;
|
||||
std::cin >> x >> y >> weight;
|
||||
graph[x].push_back(std::make_pair(weight, y));
|
||||
graph[y].push_back(std::make_pair(weight, x));
|
||||
}
|
||||
|
||||
// Selecting 1 as the starting node
|
||||
int minimum_cost = prim(1, graph);
|
||||
std::cout << minimum_cost << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Topological Sort
|
||||
* Algorithm](https://en.wikipedia.org/wiki/Topological_sorting)
|
||||
* @details
|
||||
* Topological sorting of a directed graph is a linear ordering or its vertices
|
||||
* such that for every directed edge (u,v) from vertex u to vertex v, u comes
|
||||
* before v in the oredering.
|
||||
*
|
||||
* A topological sort is possible only in a directed acyclic graph (DAG).
|
||||
* This file contains code of finding topological sort using Kahn's Algorithm
|
||||
* which involves using Depth First Search technique
|
||||
*/
|
||||
|
||||
#include <algorithm> // For std::reverse
|
||||
#include <cassert> // For assert
|
||||
#include <iostream> // For IO operations
|
||||
#include <stack> // For std::stack
|
||||
#include <stdexcept> // For std::invalid_argument
|
||||
#include <vector> // For std::vector
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
|
||||
/**
|
||||
* @namespace topological_sort
|
||||
* @brief Topological Sort Algorithm
|
||||
*/
|
||||
namespace topological_sort {
|
||||
/**
|
||||
* @class Graph
|
||||
* @brief Class that represents a directed graph and provides methods for
|
||||
* manipulating the graph
|
||||
*/
|
||||
class Graph {
|
||||
private:
|
||||
int n; // Number of nodes
|
||||
std::vector<std::vector<int>> adj; // Adjacency list representation
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for the Graph class
|
||||
* @param nodes Number of nodes in the graph
|
||||
*/
|
||||
Graph(int nodes) : n(nodes), adj(nodes) {}
|
||||
|
||||
/**
|
||||
* @brief Function that adds an edge between two nodes or vertices of graph
|
||||
* @param u Start node of the edge
|
||||
* @param v End node of the edge
|
||||
*/
|
||||
void addEdge(int u, int v) { adj[u].push_back(v); }
|
||||
|
||||
/**
|
||||
* @brief Get the adjacency list of the graph
|
||||
* @returns A reference to the adjacency list
|
||||
*/
|
||||
const std::vector<std::vector<int>>& getAdjacencyList() const {
|
||||
return adj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the number of nodes in the graph
|
||||
* @returns The number of nodes
|
||||
*/
|
||||
int getNumNodes() const { return n; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function to perform Depth First Search on the graph
|
||||
* @param v Starting vertex for depth-first search
|
||||
* @param visited Array representing whether each node has been visited
|
||||
* @param graph Adjacency list of the graph
|
||||
* @param s Stack containing the vertices for topological sorting
|
||||
*/
|
||||
void dfs(int v, std::vector<int>& visited,
|
||||
const std::vector<std::vector<int>>& graph, std::stack<int>& s) {
|
||||
visited[v] = 1;
|
||||
for (int neighbour : graph[v]) {
|
||||
if (!visited[neighbour]) {
|
||||
dfs(neighbour, visited, graph, s);
|
||||
}
|
||||
}
|
||||
s.push(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the topological sort of the graph
|
||||
* @param g Graph object
|
||||
* @returns A vector containing the topological order of nodes
|
||||
*/
|
||||
std::vector<int> topologicalSort(const Graph& g) {
|
||||
int n = g.getNumNodes();
|
||||
const auto& adj = g.getAdjacencyList();
|
||||
std::vector<int> visited(n, 0);
|
||||
std::stack<int> s;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!visited[i]) {
|
||||
dfs(i, visited, adj, s);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> ans;
|
||||
while (!s.empty()) {
|
||||
int elem = s.top();
|
||||
s.pop();
|
||||
ans.push_back(elem);
|
||||
}
|
||||
|
||||
if (ans.size() < n) { // Cycle detected
|
||||
throw std::invalid_argument("cycle detected in graph");
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
} // namespace topological_sort
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
std::cout << "Testing for graph 1\n";
|
||||
int n_1 = 6;
|
||||
graph::topological_sort::Graph graph1(n_1);
|
||||
graph1.addEdge(4, 0);
|
||||
graph1.addEdge(5, 0);
|
||||
graph1.addEdge(5, 2);
|
||||
graph1.addEdge(2, 3);
|
||||
graph1.addEdge(3, 1);
|
||||
graph1.addEdge(4, 1);
|
||||
std::vector<int> ans_1 = graph::topological_sort::topologicalSort(graph1);
|
||||
std::vector<int> expected_1 = {5, 4, 2, 3, 1, 0};
|
||||
std::cout << "Topological Sorting Order: ";
|
||||
for (int i : ans_1) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
assert(ans_1 == expected_1);
|
||||
std::cout << "Test Passed\n\n";
|
||||
|
||||
// Test 2
|
||||
std::cout << "Testing for graph 2\n";
|
||||
int n_2 = 5;
|
||||
graph::topological_sort::Graph graph2(n_2);
|
||||
graph2.addEdge(0, 1);
|
||||
graph2.addEdge(0, 2);
|
||||
graph2.addEdge(1, 2);
|
||||
graph2.addEdge(2, 3);
|
||||
graph2.addEdge(1, 3);
|
||||
graph2.addEdge(2, 4);
|
||||
std::vector<int> ans_2 = graph::topological_sort::topologicalSort(graph2);
|
||||
std::vector<int> expected_2 = {0, 1, 2, 4, 3};
|
||||
std::cout << "Topological Sorting Order: ";
|
||||
for (int i : ans_2) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
assert(ans_2 == expected_2);
|
||||
std::cout << "Test Passed\n\n";
|
||||
|
||||
// Test 3 - Graph with cycle
|
||||
std::cout << "Testing for graph 3\n";
|
||||
int n_3 = 3;
|
||||
graph::topological_sort::Graph graph3(n_3);
|
||||
graph3.addEdge(0, 1);
|
||||
graph3.addEdge(1, 2);
|
||||
graph3.addEdge(2, 0);
|
||||
try {
|
||||
graph::topological_sort::topologicalSort(graph3);
|
||||
} catch (std::invalid_argument& err) {
|
||||
assert(std::string(err.what()) == "cycle detected in graph");
|
||||
}
|
||||
std::cout << "Test Passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
std::vector<int> topoSortKahn(int N, const std::vector<std::vector<int> > &adj);
|
||||
|
||||
int main() {
|
||||
int nodes = 0, edges = 0;
|
||||
std::cin >> edges >> nodes;
|
||||
if (edges == 0 || nodes == 0) {
|
||||
return 0;
|
||||
}
|
||||
int u = 0, v = 0;
|
||||
|
||||
std::vector<std::vector<int> > graph(nodes);
|
||||
// create graph
|
||||
// example
|
||||
// 6 6
|
||||
// 5 0 5 2 2 3 4 0 4 1 1 3
|
||||
|
||||
for (int i = 0; i < edges; i++) {
|
||||
std::cin >> u >> v;
|
||||
graph[u].push_back(v);
|
||||
}
|
||||
|
||||
std::vector<int> topo = topoSortKahn(nodes, graph);
|
||||
// topologically sorted nodes
|
||||
for (int i = 0; i < nodes; i++) {
|
||||
std::cout << topo[i] << " ";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> topoSortKahn(int V,
|
||||
const std::vector<std::vector<int> > &adj) {
|
||||
std::vector<bool> vis(V + 1, false);
|
||||
std::vector<int> deg(V + 1, 0);
|
||||
for (int i = 0; i < V; i++) {
|
||||
for (int j : adj[i]) {
|
||||
deg[j]++;
|
||||
}
|
||||
}
|
||||
std::queue<int> q;
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (deg[i] == 0) {
|
||||
q.push(i);
|
||||
vis[i] = true;
|
||||
}
|
||||
}
|
||||
std::vector<int> arr(V + 1, 0);
|
||||
int count = 0;
|
||||
while (!q.empty()) {
|
||||
int cur = q.front();
|
||||
q.pop();
|
||||
arr[count++] = cur;
|
||||
for (int i : adj[cur]) {
|
||||
if (!vis[i]) {
|
||||
deg[i]--;
|
||||
if (deg[i] == 0) {
|
||||
q.push(i);
|
||||
vis[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Travelling Salesman Problem]
|
||||
* (https://en.wikipedia.org/wiki/Travelling_salesman_problem) implementation
|
||||
*
|
||||
* @author [Mayank Mamgain](http://github.com/Mayank17M)
|
||||
*
|
||||
* @details
|
||||
* Travelling salesman problem asks:
|
||||
* Given a list of cities and the distances between each pair of cities, what is
|
||||
* the shortest possible route that visits each city exactly once and returns to
|
||||
* the origin city?
|
||||
* TSP can be modeled as an undirected weighted graph, such that cities are the
|
||||
* graph's vertices, paths are the graph's edges, and a path's distance is the
|
||||
* edge's weight. It is a minimization problem starting and finishing at a
|
||||
* specified vertex after having visited each other vertex exactly once.
|
||||
* This is the naive implementation of the problem.
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::min
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <limits> /// for limits of integral types
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace graph
|
||||
* @brief Graph Algorithms
|
||||
*/
|
||||
namespace graph {
|
||||
/**
|
||||
* @brief Function calculates the minimum path distance that will cover all the
|
||||
* cities starting from the source.
|
||||
*
|
||||
* @param cities matrix representation of cities
|
||||
* @param src Point from where salesman is starting
|
||||
* @param V number of vertices in the graph
|
||||
*
|
||||
*/
|
||||
int TravellingSalesmanProblem(std::vector<std::vector<uint32_t>> *cities,
|
||||
int32_t src, uint32_t V) {
|
||||
//// vtx stores the vertexs of the graph
|
||||
std::vector<uint32_t> vtx;
|
||||
for (uint32_t i = 0; i < V; i++) {
|
||||
if (i != src) {
|
||||
vtx.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
//// store minimum weight Hamiltonian Cycle.
|
||||
int32_t min_path = 2147483647;
|
||||
do {
|
||||
//// store current Path weight(cost)
|
||||
int32_t curr_weight = 0;
|
||||
|
||||
//// compute current path weight
|
||||
int k = src;
|
||||
for (int i : vtx) {
|
||||
curr_weight += (*cities)[k][i];
|
||||
k = i;
|
||||
}
|
||||
curr_weight += (*cities)[k][src];
|
||||
|
||||
//// update minimum
|
||||
min_path = std::min(min_path, curr_weight);
|
||||
|
||||
} while (next_permutation(vtx.begin(), vtx.end()));
|
||||
|
||||
return min_path;
|
||||
}
|
||||
} // namespace graph
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void tests() {
|
||||
std::cout << "Initiatinig Predefined Tests..." << std::endl;
|
||||
std::cout << "Initiating Test 1..." << std::endl;
|
||||
std::vector<std::vector<uint32_t>> cities = {
|
||||
{0, 20, 42, 35}, {20, 0, 30, 34}, {42, 30, 0, 12}, {35, 34, 12, 0}};
|
||||
uint32_t V = cities.size();
|
||||
assert(graph::TravellingSalesmanProblem(&cities, 0, V) == 97);
|
||||
std::cout << "1st test passed..." << std::endl;
|
||||
|
||||
std::cout << "Initiating Test 2..." << std::endl;
|
||||
cities = {{0, 5, 10, 15}, {5, 0, 20, 30}, {10, 20, 0, 35}, {15, 30, 35, 0}};
|
||||
V = cities.size();
|
||||
assert(graph::TravellingSalesmanProblem(&cities, 0, V) == 75);
|
||||
std::cout << "2nd test passed..." << std::endl;
|
||||
|
||||
std::cout << "Initiating Test 3..." << std::endl;
|
||||
cities = {
|
||||
{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}};
|
||||
V = cities.size();
|
||||
assert(graph::TravellingSalesmanProblem(&cities, 0, V) == 80);
|
||||
std::cout << "3rd test passed..." << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // run self-test implementations
|
||||
std::vector<std::vector<uint32_t>> cities = {
|
||||
{0, 5, 10, 15}, {5, 0, 20, 30}, {10, 20, 0, 35}, {15, 30, 35, 0}};
|
||||
uint32_t V = cities.size();
|
||||
std::cout << graph::TravellingSalesmanProblem(&cities, 0, V) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user