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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:37:28 +08:00
commit 29cfe479ab
432 changed files with 68491 additions and 0 deletions
+20
View File
@@ -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} )
+294
View File
@@ -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;
}
+203
View File
@@ -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;
}
+148
View File
@@ -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;
}
+120
View File
@@ -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;
}
+314
View File
@@ -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;
}
+133
View File
@@ -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;
}
+207
View File
@@ -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;
}
+180
View File
@@ -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;
}
+145
View File
@@ -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;
}
+325
View File
@@ -0,0 +1,325 @@
/**
* @file
* @brief Implementation of [HopcroftKarp](https://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm) algorithm.
* @details
* The HopcroftKarp 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 us 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;
}
+171
View File
@@ -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;
}
+126
View File
@@ -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;
}
+129
View File
@@ -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;
}
+64
View File
@@ -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;
}
+258
View File
@@ -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;
}
+151
View File
@@ -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;
}
+57
View File
@@ -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;
}
+189
View File
@@ -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;
}
+68
View File
@@ -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;
}
+112
View File
@@ -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;
}