├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── Array └── difference_array_range_update.cpp ├── Backtracking ├── graph_coloring.cpp ├── n_queens_problem.cpp └── tempCodeRunnerFile.cpp ├── Binary Search ├── aggresive_cows.cpp ├── book_allocation.cpp ├── first_and_last_occurence_of_element_in_array.cpp ├── search_element_in_rotated_sorted_array.cpp └── sqrt_floored_of_a_number.cpp ├── Dynamic Programming ├── README.md └── edit_distance.cpp ├── Graphs ├── BFS.cpp ├── DFS.cpp ├── Disjoint_Set_Union_Find │ ├── dsu.cpp │ ├── graph_cycle_detection_dsu.cpp │ ├── introduction.txt │ └── problems │ │ └── colorful_array.cpp ├── Euler_Tour │ └── euler_tour_of_tree.cpp ├── Maximum_Flow │ ├── Edmonds-Karp_Algorithm.cpp │ ├── Ford-Fulkerson_Algorithm.txt │ └── introduction.txt ├── Minimum_Spanning_Tree │ ├── introduction.txt │ ├── kruskal.cpp │ ├── prims.cpp │ └── second-mst-kruskal.cpp ├── Shortest_Path │ ├── bellman_ford.cpp │ ├── dijkstra_multi_source_CP.cpp │ ├── dijkstra_single_source_CP.cpp │ ├── floyd-warshall.cpp │ └── introduction.txt ├── Strongly_Connected_Components │ ├── kosaraju_scc.cpp │ └── tarjan.cpp ├── Travelling_Salesman │ └── tsp_dp.cpp ├── cycle_detection_dfs.cpp ├── graph_bipartite.cpp ├── introduction.txt └── topological_sort.cpp ├── Greedy ├── README.md ├── activity_selection_problem.cpp ├── expedition_cows.cpp ├── job_sequencing_dsu_nlogn.cpp └── job_sequencing_n2.cpp ├── Linked List └── linked_list.cpp ├── Number Theory ├── count_and_sum_of_divisors.cpp ├── euclidean_gcd.cpp ├── euler_totient_function.cpp ├── extended_euclidean_gcd.cpp ├── modular_exponentiation.cpp ├── modular_multiplicative_inverse.cpp └── primality_test_fermat.cpp ├── Queue └── queue_ll.py ├── README.md ├── Search ├── binary_search.py └── linear_search.py ├── Square Root Decomposition ├── number_of_distinct_elements_in_range_l_to_r.cpp ├── number_of_elements_greater_than_k_in_the_range_l_to_r_and_update.cpp ├── range_sum_point_update.cpp └── range_sum_range_update.cpp ├── Stack ├── next_greater_element.cpp ├── next_smaller_element ├── next_smaller_element.cpp └── stack_ll.py ├── Strings ├── kmp.cpp ├── problems │ └── count_of_cyclic_permutation_xor_with_binary_string_0.cpp └── z-algo.cpp ├── Trees ├── Binary_Search_Tree │ └── bst.cpp └── min_node_of_subtree_dp.cpp ├── Trie ├── problems │ ├── maximum_xor_of_two_array_elements.cpp │ └── shortest_unique_prefix_for_every_word.cpp └── trie.cpp ├── template.cpp └── template_small.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | !*.cpp 3 | !*.py 4 | !*.java 5 | !*.c -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "g++ - Build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${fileDirname}/${fileBasenameNoExtension}", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${fileDirname}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | "preLaunchTask": "C/C++: g++ build active file", 26 | "miDebuggerPath": "/usr/bin/gdb" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "forward_list": "cpp", 4 | "iostream": "cpp", 5 | "numeric": "cpp", 6 | "*.tcc": "cpp", 7 | "deque": "cpp", 8 | "list": "cpp", 9 | "string": "cpp", 10 | "unordered_map": "cpp", 11 | "unordered_set": "cpp", 12 | "vector": "cpp", 13 | "ostream": "cpp", 14 | "any": "cpp", 15 | "array": "cpp", 16 | "atomic": "cpp", 17 | "bit": "cpp", 18 | "bitset": "cpp", 19 | "cctype": "cpp", 20 | "cfenv": "cpp", 21 | "charconv": "cpp", 22 | "chrono": "cpp", 23 | "cinttypes": "cpp", 24 | "clocale": "cpp", 25 | "cmath": "cpp", 26 | "codecvt": "cpp", 27 | "complex": "cpp", 28 | "condition_variable": "cpp", 29 | "csetjmp": "cpp", 30 | "csignal": "cpp", 31 | "cstdarg": "cpp", 32 | "cstddef": "cpp", 33 | "cstdint": "cpp", 34 | "cstdio": "cpp", 35 | "cstdlib": "cpp", 36 | "cstring": "cpp", 37 | "ctime": "cpp", 38 | "cuchar": "cpp", 39 | "cwchar": "cpp", 40 | "cwctype": "cpp", 41 | "map": "cpp", 42 | "set": "cpp", 43 | "exception": "cpp", 44 | "algorithm": "cpp", 45 | "functional": "cpp", 46 | "iterator": "cpp", 47 | "memory": "cpp", 48 | "memory_resource": "cpp", 49 | "optional": "cpp", 50 | "random": "cpp", 51 | "ratio": "cpp", 52 | "regex": "cpp", 53 | "string_view": "cpp", 54 | "system_error": "cpp", 55 | "tuple": "cpp", 56 | "type_traits": "cpp", 57 | "utility": "cpp", 58 | "fstream": "cpp", 59 | "future": "cpp", 60 | "initializer_list": "cpp", 61 | "iomanip": "cpp", 62 | "iosfwd": "cpp", 63 | "istream": "cpp", 64 | "limits": "cpp", 65 | "mutex": "cpp", 66 | "new": "cpp", 67 | "scoped_allocator": "cpp", 68 | "shared_mutex": "cpp", 69 | "sstream": "cpp", 70 | "stdexcept": "cpp", 71 | "streambuf": "cpp", 72 | "thread": "cpp", 73 | "typeindex": "cpp", 74 | "typeinfo": "cpp", 75 | "valarray": "cpp", 76 | "variant": "cpp" 77 | } 78 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: g++ build active file", 6 | "command": "/usr/bin/g++", 7 | "args": [ 8 | "-g", 9 | "${file}", 10 | "-o", 11 | "${fileDirname}/${fileBasenameNoExtension}" 12 | ], 13 | "options": { 14 | "cwd": "${fileDirname}" 15 | }, 16 | "problemMatcher": [ 17 | "$gcc" 18 | ], 19 | "group": { 20 | "kind": "build", 21 | "isDefault": true 22 | }, 23 | "detail": "Task generated by Debugger." 24 | } 25 | ], 26 | "version": "2.0.0" 27 | } -------------------------------------------------------------------------------- /Array/difference_array_range_update.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Given an array of n integers, perform q queries on it. In each query, you are given two integers L and R. 12 | // Increment all values in the range L to R (inclusive). After finishing all queries, print the final array 13 | 14 | // Time complexity: O(n) | Space complexity: O(n) 15 | int main(int argc, char const *argv[]) { 16 | int n; 17 | cin >> n; 18 | vi arr(n); 19 | for (int i = 0; i < n; i++) cin >> arr[i]; 20 | vi diff(n + 1, 0); 21 | diff[0] = arr[0]; 22 | for (int i = 1; i < n; i++) diff[i] = arr[i] - arr[i - 1]; 23 | int q; 24 | cin >> q; 25 | while (q--) { 26 | int l, r; 27 | cin >> l >> r; 28 | diff[l] += 1; 29 | diff[r + 1] -= 1; 30 | } 31 | arr[0] = diff[0]; 32 | for (int i = 1; i < n; i++) arr[i] = diff[i] + arr[i - 1]; 33 | for (int i = 0; i < n; i++) cout << arr[i] << ' '; 34 | cout << endl; 35 | return 0; 36 | } 37 | 38 | /* 39 | Input: 40 | 5 41 | 1 2 3 4 5 42 | 3 43 | 0 2 44 | 1 3 45 | 2 3 46 | 47 | Output: 48 | 2 4 6 6 5 49 | 50 | Steps: 51 | Initial array: 1 2 3 4 5 52 | After 1st query: 2 3 4 4 5 53 | After 2nd query: 2 4 5 5 5 54 | After 3rd query: 2 4 6 6 5 55 | */ -------------------------------------------------------------------------------- /Backtracking/graph_coloring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Checking if any neighbours of vertex v is having the color 'color'. If so, then we can't put the same color on vertex v. 12 | bool isSafe(int v, int color, const vector &graph, const vi &nodeColors) { 13 | for (int neighbour : graph[v]) { 14 | if (nodeColors[neighbour] == color) return false; 15 | } 16 | return true; 17 | } 18 | 19 | // Time complexity: O(n ^ k) [k = number of given colors] | Space Complexity: O(n) 20 | void countWays(int i, int &count, vi &nodeColors, const vector &graph, const vi &colors) { 21 | // If all vertices have colors, then we have a valid configuration (all colors will be valid due to the isSafe condition below) 22 | if (i == graph.size()) { 23 | count += 1; 24 | // We can print nodeColors array here to get the colors for all the vertices 25 | return; 26 | } 27 | for (int color : colors) { 28 | if (isSafe(i, color, graph, nodeColors)) { 29 | // We check if we can put the current 'color' in vertex i. If it's possible we put it and continue with the next vertex. 30 | // Then backtrack and reset the color to -1 indicating no color and check with other colors in next iterations. 31 | nodeColors[i] = color; 32 | countWays(i + 1, count, nodeColors, graph, colors); 33 | nodeColors[i] = -1; 34 | } 35 | } 36 | } 37 | 38 | int main(int argc, char const *argv[]) { 39 | int n, m, c; 40 | cin >> n >> m >> c; 41 | vector graph(n + 1); 42 | for (int i = 0; i < m; i++) { 43 | int u, v; 44 | cin >> u >> v; 45 | graph[u].pb(v); 46 | graph[v].pb(u); 47 | } 48 | vi colors(c), nodeColors(n + 1, -1); 49 | for (int i = 0; i < c; i++) colors[i] = i + 1; 50 | int possibleWays = 0; 51 | countWays(1, possibleWays, nodeColors, graph, colors); 52 | cout << possibleWays << endl; 53 | } 54 | 55 | /* 56 | Input: 57 | 4 5 4 58 | 1 3 59 | 1 4 60 | 2 3 61 | 2 4 62 | 3 4 63 | Output: 64 | 48 65 | 66 | Input: 67 | 3 3 3 68 | 1 2 69 | 2 3 70 | 3 1 71 | Output: 72 | 6 73 | */ -------------------------------------------------------------------------------- /Backtracking/n_queens_problem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Solution { 5 | public: 6 | bool isSafe(int r, int c, vector &board) { 7 | for (int j = c - 1; j >= 0; j--) { 8 | if (board[r][j] == 'Q') return false; 9 | } 10 | for (int j = c + 1; j < board.size(); j++) { 11 | if (board[r][j] == 'Q') return false; 12 | } 13 | for (int i = r - 1; i >= 0; i--) { 14 | if (board[i][c] == 'Q') return false; 15 | } 16 | for (int i = r + 1; i < board.size(); i++) { 17 | if (board[i][c] == 'Q') return false; 18 | } 19 | for (int i = r - 1, j = c - 1; i >= 0 && j >= 0; i--, j--) { 20 | if (board[i][j] == 'Q') return false; 21 | } 22 | for (int i = r - 1, j = c + 1; i >= 0 && j < board.size(); i--, j++) { 23 | if (board[i][j] == 'Q') return false; 24 | } 25 | for (int i = r + 1, j = c + 1; i < board.size() && j < board.size(); i++, j++) { 26 | if (board[i][j] == 'Q') return false; 27 | } 28 | for (int i = r + 1, j = c - 1; i < board.size() && j >= 0; i++, j--) { 29 | if (board[i][j] == 'Q') return false; 30 | } 31 | return true; 32 | } 33 | void recurse(int r, vector &board, set> &res) { 34 | if (r == -1) { 35 | res.insert(board); 36 | return; 37 | } 38 | for (int j = 0; j < board.size(); j++) { 39 | if (board[r][j] == 'Q') continue; 40 | if (isSafe(r, j, board)) { 41 | board[r][j] = 'Q'; 42 | recurse(r - 1, board, res); 43 | board[r][j] = '.'; 44 | } 45 | } 46 | } 47 | vector> solveNQueens(int n) { 48 | string s = ""; 49 | for (int i = 0; i < n; i++) s += '.'; 50 | vector board(n, s); 51 | set> res; 52 | recurse(n - 1, board, res); 53 | vector> ans; 54 | for (auto it : res) ans.push_back(it); 55 | return ans; 56 | } 57 | }; 58 | 59 | int main(int argc, char const *argv[]) { 60 | int n; 61 | cin >> n; 62 | Solution s; 63 | vector> ans = s.solveNQueens(n); 64 | cout << ans.size() << endl; 65 | 66 | // for (auto it : ans) { 67 | // // for (auto itt : it) cout << itt << endl; 68 | // } 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Backtracking/tempCodeRunnerFile.cpp: -------------------------------------------------------------------------------- 1 | // for (auto it : ans) { 2 | // // for (auto itt : it) cout << itt << endl; 3 | // } -------------------------------------------------------------------------------- /Binary Search/aggresive_cows.cpp: -------------------------------------------------------------------------------- 1 | // https://www.spoj.com/problems/AGGRCOW/ 2 | #include 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | const int INF = 0x3f3f3f3f; 10 | const int mod = 1e9 + 7; 11 | 12 | int main(int argc, char const *argv[]) { 13 | int t; 14 | cin >> t; 15 | while (t--) { 16 | int n, c; 17 | cin >> n >> c; 18 | vi arr(n); 19 | for (int i = 0; i < n; i++) cin >> arr[i]; 20 | sort(arr.begin(), arr.end()); 21 | int start = arr[0], end = arr[n - 1], ans = 0; 22 | while (start <= end) { 23 | int mid = start + (end - start) / 2; 24 | int tmpc = c - 1, prev = 0; 25 | for (int i = 1; i < n; i++) { 26 | if (tmpc == 0) break; 27 | if (arr[i] - arr[prev] >= mid) tmpc -= 1, prev = i; 28 | } 29 | if (tmpc == 0) { 30 | ans = mid; 31 | start = mid + 1; 32 | } else { 33 | end = mid - 1; 34 | } 35 | } 36 | cout << ans << endl; 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Binary Search/book_allocation.cpp: -------------------------------------------------------------------------------- 1 | // https://www.interviewbit.com/problems/allocate-books/ 2 | #include 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | bool isPossible(int val, vector &arr, int b) { 9 | int cnt = 1, currSum = 0; 10 | for (int i = 0; i < arr.size(); i++) { 11 | if (arr[i] > val) return false; 12 | if (currSum + arr[i] <= val) 13 | currSum += arr[i]; 14 | else { 15 | cnt += 1; 16 | currSum = arr[i]; 17 | } 18 | } 19 | return cnt <= b; 20 | } 21 | 22 | int books(vector &arr, int b) { 23 | if (b > arr.size()) return -1; 24 | int start = *max_element(arr.begin(), arr.end()), end = accumulate(arr.begin(), arr.end(), 0); 25 | int ans = -1; 26 | while (start <= end) { 27 | int mid = start + (end - start) / 2; 28 | if (isPossible(mid, arr, b)) { 29 | ans = mid; 30 | end = mid - 1; 31 | } else { 32 | start = mid + 1; 33 | } 34 | } 35 | return ans; 36 | } 37 | 38 | int main(int argc, char const *argv[]) { 39 | int n, b; 40 | cin >> n >> b; 41 | vector arr(n); 42 | for (int i = 0; i < n; i++) cin >> arr[i]; 43 | cout << books(arr, b); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Binary Search/first_and_last_occurence_of_element_in_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | int main(int argc, char const *argv[]) { 12 | int n, k; 13 | cin >> n >> k; 14 | vi arr(n); 15 | for (int i = 0; i < n; i++) cin >> arr[i]; 16 | int first_occ = -1, last_occ = -1; 17 | int start = 0, end = n - 1; 18 | while (start <= end) { 19 | int mid = start + (end - start) / 2; 20 | if (arr[mid] == k) { 21 | first_occ = mid; 22 | end = mid - 1; 23 | } else if (arr[mid] < k) { 24 | start = mid + 1; 25 | } else { 26 | end = mid - 1; 27 | } 28 | } 29 | start = 0, end = n - 1; 30 | while (start <= end) { 31 | int mid = start + (end - start) / 2; 32 | if (arr[mid] == k) { 33 | last_occ = mid; 34 | start = mid + 1; 35 | } else if (arr[mid] < k) { 36 | start = mid + 1; 37 | } else { 38 | end = mid - 1; 39 | } 40 | } 41 | cout << "First occurence of " << k << ": " << first_occ << endl; 42 | cout << "Last occurence of " << k << ": " << last_occ << endl; 43 | return 0; 44 | } 45 | 46 | /* 47 | Input: 48 | 10 3 49 | 1 2 3 3 3 3 5 5 5 7 50 | 51 | Output: 52 | First occurence of 3: 2 53 | Last occurence of 3: 5 54 | */ -------------------------------------------------------------------------------- /Binary Search/search_element_in_rotated_sorted_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Given a sorted array with some rotations ([1, 2, 3] -> [3, 1, 2] on first rotation), find whether a given number exists in the array 12 | 13 | // Time complexity: O(log(n)) 14 | int main(int argc, char const *argv[]) { 15 | int n, k; 16 | cin >> n >> k; 17 | vi arr(n); 18 | for (int i = 0; i < n; i++) cin >> arr[i]; 19 | int start = 0, end = n - 1; 20 | int index = -1; 21 | while (start <= end) { 22 | int mid = start + (end - start) / 2; 23 | if (arr[mid] == k) { 24 | index = mid; 25 | break; 26 | } 27 | if (arr[start] <= arr[mid]) { 28 | if (k >= arr[start] && k <= arr[mid]) { 29 | end = mid - 1; 30 | } else { 31 | start = mid + 1; 32 | } 33 | } else { 34 | if (k >= arr[mid] && k <= arr[end]) { 35 | start = mid + 1; 36 | } else { 37 | end = mid - 1; 38 | } 39 | } 40 | } 41 | cout << index << endl; 42 | return 0; 43 | } 44 | 45 | /* 46 | Input: 47 | 6 7 48 | 7 8 1 2 3 4 49 | 50 | Output: 51 | 0 52 | */ -------------------------------------------------------------------------------- /Binary Search/sqrt_floored_of_a_number.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Find the square root of a number using binary search upto a certain precision 12 | 13 | // Time complexity: O(log(n)) 14 | int main(int argc, char const *argv[]) { 15 | int n; 16 | cin >> n; 17 | int start = 0, end = n; 18 | double ans = 0; 19 | 20 | // Binary search to get the integer part 21 | while (start <= end) { 22 | int mid = start + (end - start) / 2; 23 | if (mid * mid <= n) { 24 | ans = mid; 25 | start = mid + 1; 26 | } else { 27 | end = mid - 1; 28 | } 29 | } 30 | 31 | // Brute force to get the decimal part (Low time complexity as we consider of a few decimal places) 32 | int precission = 3; 33 | double inc = 0.1; 34 | for (int i = 1; i <= precission; i++) { 35 | while (ans * ans <= n) { 36 | ans += inc; 37 | } 38 | ans -= inc; 39 | inc = inc / 10; 40 | } 41 | cout << ans << endl; 42 | return 0; 43 | } 44 | 45 | /* 46 | Input: 47 | 3 48 | 49 | Output: 50 | 1.732 51 | */ -------------------------------------------------------------------------------- /Dynamic Programming/README.md: -------------------------------------------------------------------------------- 1 | ### Contains the solutions of the most common dynamic programming problems. 2 | -------------------------------------------------------------------------------- /Dynamic Programming/edit_distance.cpp: -------------------------------------------------------------------------------- 1 | // https://practice.geeksforgeeks.org/problems/edit-distance3702/1 2 | #include 3 | using namespace std; 4 | 5 | class Solution { 6 | public: 7 | vector> dp; 8 | int recurse(int n, int m, string s, string t) { 9 | if (n == 0) return m; 10 | if (m == 0) return n; 11 | if (dp[n][m] != -1) return dp[n][m]; 12 | if (s[n - 1] == t[m - 1]) return dp[n][m] = recurse(n - 1, m - 1, s, t); 13 | return dp[n][m] = 1 + min({recurse(n - 1, m - 1, s, t), recurse(n, m - 1, s, t), recurse(n - 1, m, s, t)}); 14 | } 15 | int editDistance(string s, string t) { 16 | // Code here 17 | dp.resize(s.size() + 10, vector(t.size() + 10, -1)); 18 | int ans = recurse(s.size(), t.size(), s, t); 19 | return ans; 20 | } 21 | }; 22 | 23 | int main() { 24 | int T; 25 | cin >> T; 26 | while (T--) { 27 | string s, t; 28 | cin >> s >> t; 29 | Solution ob; 30 | int ans = ob.editDistance(s, t); 31 | cout << ans << "\n"; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Graphs/BFS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | /* 6 | # Breadth First Search Traversal. 7 | # Requires a queue. 8 | # The edges of the graph can be unidirectional/bidirectional. 9 | # Time complexity: O(V + E) | Space complexity: O(V) 10 | */ 11 | 12 | class Vertex { 13 | public: 14 | string data; 15 | vector neighbours; 16 | Vertex(string val) { 17 | data = val; 18 | } 19 | }; 20 | 21 | class Graph { 22 | private: 23 | vector vertexList; 24 | 25 | public: 26 | int getVertexListSize() { 27 | return vertexList.size(); 28 | } 29 | void addVertex(string data) { 30 | vertexList.push_back(Vertex(data)); 31 | } 32 | // Directed 33 | void set_edge(int u, int v) { 34 | vertexList[u].neighbours.push_back(v); 35 | } 36 | 37 | // Normal BFS 38 | void bfs() { 39 | queue q; 40 | vector visited(vertexList.size(), false); 41 | for (int i = 0; i < vertexList.size(); i++) { 42 | if (!visited[i]) { 43 | visited[i] = true; 44 | q.push(i); 45 | while (!q.empty()) { 46 | int p = q.front(); 47 | q.pop(); 48 | cout << vertexList[p].data << " "; 49 | for (int x : vertexList[p].neighbours) { 50 | if (!visited[x]) { 51 | visited[x] = true; 52 | q.push(x); 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | // Calculates distance from root node...assuming its undirected and tree like 60 | vector bfs_calc_distance() { 61 | queue q; 62 | vector visited(vertexList.size(), false); 63 | vector distance(vertexList.size(), -1); 64 | for (int i = 0; i < vertexList.size(); i++) { 65 | if (!visited[i]) { 66 | visited[i] = true; 67 | q.push(i); 68 | distance[i] = 0; 69 | while (!q.empty()) { 70 | int p = q.front(); 71 | q.pop(); 72 | for (int x : vertexList[p].neighbours) { 73 | if (!visited[x]) { 74 | visited[x] = true; 75 | q.push(x); 76 | distance[x] = distance[p] + 1; 77 | } 78 | } 79 | } 80 | } 81 | } 82 | return distance; 83 | } 84 | 85 | // Calculates parent of each ndoe...assuming its undirected 86 | vector bfs_calc_parent() { 87 | queue q; 88 | vector visited(vertexList.size(), false); 89 | vector parent(vertexList.size(), -1); 90 | for (int i = 0; i < vertexList.size(); i++) { 91 | if (!visited[i]) { 92 | visited[i] = true; 93 | q.push(i); 94 | while (!q.empty()) { 95 | int p = q.front(); 96 | q.pop(); 97 | for (int x : vertexList[p].neighbours) { 98 | if (!visited[x]) { 99 | visited[x] = true; 100 | q.push(x); 101 | parent[x] = p; 102 | } 103 | } 104 | } 105 | } 106 | } 107 | return parent; 108 | } 109 | }; 110 | 111 | int main() { 112 | Graph g; 113 | g.addVertex("A"); // 0 114 | g.addVertex("B"); // 1 115 | g.addVertex("C"); // 2 116 | g.addVertex("D"); // 3 117 | g.addVertex("E"); // 4 118 | g.addVertex("F"); // 5 119 | g.addVertex("G"); // 6 120 | g.addVertex("H"); // 7 121 | g.set_edge(0, 1); 122 | g.set_edge(0, 5); 123 | g.set_edge(0, 6); 124 | g.set_edge(1, 2); 125 | g.set_edge(1, 3); 126 | g.set_edge(3, 4); 127 | g.set_edge(6, 7); 128 | g.bfs(); 129 | cout << endl; 130 | vector dist = g.bfs_calc_distance(); 131 | for (auto it : dist) cout << it << " "; 132 | cout << endl; 133 | vector par = g.bfs_calc_parent(); 134 | for (auto it : par) cout << it << " "; 135 | cout << endl; 136 | for (int i = 0; i < g.getVertexListSize(); i++) { 137 | cout << i << "\t"; 138 | int cur = par[i]; 139 | deque path; 140 | path.push_front(i); 141 | while (cur != -1) { 142 | path.push_front(cur); 143 | cur = par[cur]; 144 | } 145 | for (auto it : path) cout << it << " "; 146 | path.clear(); 147 | cout << endl; 148 | } 149 | return 0; 150 | } -------------------------------------------------------------------------------- /Graphs/DFS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | /* 6 | # Depth First Search Traversal. 7 | # Requires a stack. 8 | # The edges of the graph can be unidirectional/bidirectional. 9 | # Time complexity: O(V + E) | Space complexity: O(V) 10 | */ 11 | 12 | class Vertex { 13 | public: 14 | string data; 15 | vector neighbours; 16 | Vertex(string val) { 17 | data = val; 18 | } 19 | }; 20 | 21 | class Graph { 22 | private: 23 | vector vertexList; 24 | 25 | public: 26 | void addVertex(string data) { 27 | vertexList.push_back(Vertex(data)); 28 | } 29 | void set_edge(int u, int v) { 30 | vertexList[u].neighbours.push_back(v); 31 | } 32 | void dfsUtil(int start, vector &visited) { 33 | visited[start] = true; 34 | cout << vertexList[start].data << " "; 35 | for (int x : vertexList[start].neighbours) { 36 | if (!visited[x]) { 37 | dfsUtil(x, visited); 38 | } 39 | } 40 | } 41 | void dfs() { 42 | vector visited(vertexList.size(), false); 43 | for (int i = 0; i < vertexList.size(); i++) { 44 | if (!visited[i]) { 45 | dfsUtil(i, visited); 46 | } 47 | } 48 | visited.clear(); 49 | cout << endl; 50 | } 51 | }; 52 | 53 | int main() { 54 | Graph g; 55 | g.addVertex("A"); // 0 56 | g.addVertex("B"); // 1 57 | g.addVertex("C"); // 2 58 | g.addVertex("D"); // 3 59 | g.addVertex("E"); // 4 60 | g.addVertex("F"); // 5 61 | g.set_edge(0, 3); 62 | g.set_edge(0, 4); 63 | g.set_edge(3, 2); 64 | g.set_edge(2, 4); 65 | g.set_edge(4, 1); 66 | g.set_edge(4, 5); 67 | g.set_edge(4, 3); 68 | g.dfs(); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /Graphs/Disjoint_Set_Union_Find/dsu.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | 10 | int Get(mii &parent, int a) { 11 | return parent[a] = parent[a] == a ? a : Get(parent, parent[a]); 12 | } 13 | 14 | void Union(mii &parent, mii &rank, int a, int b) { 15 | a = Get(parent, a); 16 | b = Get(parent, b); 17 | if (rank[a] == rank[b]) { 18 | rank[a]++; 19 | } 20 | if (rank[a] > rank[b]) { 21 | parent[b] = a; 22 | } else { 23 | parent[a] = b; 24 | } 25 | } 26 | 27 | int main() { 28 | mii parent, rank; 29 | for (int i = 1; i <= 9; i += 2) { 30 | parent[i] = i; 31 | rank[i] = 0; 32 | } 33 | cout << Get(parent, 1) << endl; 34 | cout << Get(parent, 5) << endl; 35 | Union(parent, rank, 1, 5); 36 | cout << Get(parent, 1) << endl; 37 | cout << Get(parent, 5) << endl; 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Graphs/Disjoint_Set_Union_Find/graph_cycle_detection_dsu.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | 10 | // Checking if cycle is present in a given graph using disjoint set data structure. 11 | 12 | int Get(mii &parent, int a) { 13 | return parent[a] = parent[a] == a ? a : Get(parent, parent[a]); 14 | } 15 | 16 | void Union(mii &parent, mii &rank, int a, int b) { 17 | a = Get(parent, a); 18 | b = Get(parent, b); 19 | if (rank[a] == rank[b]) { 20 | rank[a]++; 21 | } 22 | if (rank[a] > rank[b]) { 23 | parent[b] = a; 24 | } else { 25 | parent[a] = b; 26 | } 27 | } 28 | 29 | bool check_cycle(vector &graph) { 30 | mii parent, rank; 31 | 32 | // Initialising DSU 33 | for (int i = 0; i < graph.size(); i++) { 34 | parent[i] = i; 35 | rank[i] = 0; 36 | } 37 | for (int i = 0; i < graph.size(); i++) { 38 | for (int el : graph[i]) { 39 | int src = i; 40 | int dest = el; 41 | int src_parent = Get(parent, src); 42 | int dest_parent = Get(parent, dest); 43 | if (src_parent == dest_parent) return true; 44 | Union(parent, rank, src, dest); 45 | } 46 | } 47 | return false; 48 | } 49 | 50 | int main() { 51 | vector graph(6); 52 | graph[0].pb(1); 53 | graph[1].pb(2); 54 | graph[2].pb(4); 55 | graph[4].pb(5); 56 | graph[4].pb(3); 57 | graph[3].pb(1); 58 | bool ans = check_cycle(graph); 59 | if (ans) { 60 | cout << "Cycle found"; 61 | } else { 62 | cout << "No cycle found"; 63 | } 64 | return 0; 65 | } -------------------------------------------------------------------------------- /Graphs/Disjoint_Set_Union_Find/introduction.txt: -------------------------------------------------------------------------------- 1 | # This data structure is very useful, 2 of the many uses are ⟶ 2 | • Finding cycles in an UG 3 | • also used in Kruskal's algorithm 4 | -------------------------------------------------------------------------------- /Graphs/Disjoint_Set_Union_Find/problems/colorful_array.cpp: -------------------------------------------------------------------------------- 1 | // https://www.spoj.com/problems/CLFLARR/ 2 | #include 3 | using namespace std; 4 | 5 | #define ll long long 6 | #define vi vector 7 | #define vll vector 8 | #define pii pair 9 | #define pll pair 10 | #define pb push_back 11 | #define mp make_pair 12 | #define all(a) a.begin(), a.end() 13 | const int MOD = 1e9 + 7; 14 | const ll INF = 1e18; 15 | #define inputarr(arr, n) \ 16 | for (ll i = 0; i < n; i++) cin >> arr[i]; 17 | #define printarr(arr, n) \ 18 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 19 | 20 | ll findParent(ll x, vll &parents) { 21 | if (parents[x] == x) return x; 22 | return parents[x] = findParent(parents[x], parents); 23 | } 24 | 25 | void solve() { 26 | ll n, q; 27 | cin >> n >> q; 28 | vll parents(n + 1), arr(n, 0); 29 | for (int i = 0; i <= n; i++) parents[i] = i; 30 | vector queries; 31 | while (q--) { 32 | ll l, r, c; 33 | cin >> l >> r >> c; 34 | l--, r--; 35 | queries.pb({l, r, c}); 36 | } 37 | for (int x = queries.size() - 1; x >= 0; x--) { 38 | ll l = queries[x][0], r = queries[x][1], c = queries[x][2]; 39 | for (ll i = findParent(l, parents); i <= r; i = findParent(i, parents)) { 40 | arr[i] = c; 41 | parents[i] = i + 1; 42 | } 43 | } 44 | for (ll it : arr) cout << it << endl; 45 | } 46 | 47 | int main() { 48 | ios_base::sync_with_stdio(false); 49 | cin.tie(0); 50 | cout.tie(0); 51 | int t = 1; 52 | // cin >> t; 53 | while (t--) { 54 | solve(); 55 | } 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /Graphs/Euler_Tour/euler_tour_of_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Run dfs through the tree and fill up the timein and timeout arrays 12 | void euler_tour(int curr, int parent, vector &tree, int &timer, vi &timein, vi &timeout) { 13 | timein[curr] = ++timer; 14 | for (int child : tree[curr]) { 15 | if (child != parent) { 16 | euler_tour(child, curr, tree, timer, timein, timeout); 17 | } 18 | } 19 | timeout[curr] = timer; 20 | } 21 | 22 | // Check if x is ancestor of y in a given tree by checking if the (timein, timeout) interval of x completely overlaps the interval of y 23 | bool isAncestor(int x, int y, const vi &timein, const vi &timeout) { 24 | if (timein[x] <= timein[y] && timeout[x] >= timeout[y]) return true; 25 | return false; 26 | } 27 | 28 | int main(int argc, char const *argv[]) { 29 | int n; 30 | cin >> n; 31 | vector tree(n + 1); 32 | for (int i = 1; i <= n - 1; i++) { 33 | int u, v; 34 | cin >> u >> v; 35 | tree[u].pb(v); 36 | tree[v].pb(u); 37 | } 38 | vi time_in(n + 1), time_out(n + 1); 39 | int timer = 0; 40 | euler_tour(1, 0, tree, timer, time_in, time_out); 41 | cout << "Number of nodes: " << timer << endl; 42 | cout << "Timein and Timeout values for all nodes:" << endl; 43 | for (int i = 1; i <= n; i++) { 44 | cout << i << ' ' << time_in[i] << ' ' << time_out[i] << endl; 45 | } 46 | cout << "Is 1 ancestor of 7?" << endl; 47 | if (isAncestor(1, 7, time_in, time_out)) { 48 | cout << "YES\n"; 49 | } else { 50 | cout << "NO\n"; 51 | } 52 | return 0; 53 | } 54 | 55 | /* 56 | 9 57 | 1 2 58 | 2 4 59 | 2 5 60 | 2 6 61 | 1 3 62 | 3 7 63 | 7 8 64 | 7 9 65 | */ -------------------------------------------------------------------------------- /Graphs/Maximum_Flow/Edmonds-Karp_Algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | const int INF = 0x3f3f3f3f; 10 | const int mod = 1e9 + 7; 11 | 12 | /* 13 | # Time complexity: O(V.E^2) 14 | # Works of directed graphs 15 | # This implementation is done using an vertex adjecency list. 16 | # Algorithm: 17 | Step 1. Initialize the residual capacity matrix by assuming flow of each edge as 0 initially for every valid 18 | edge pair (i, j) & for all other pair fill it with 0 as well. Also initialize max_flow = 0. 19 | Step 2. Keep finding the augmenting path and add the min flow of the augmenting path to the max_flow. Also subtract the flow from all direct edges of the path and add to all residual edges of the path. 20 | Stop if no augmenting path is left. 21 | 22 | # Special Note: In the below algorithm, 'g' is the adjacency list of the undirected graph since we also have 23 | to use the reversed of directed edges of the original directed graph when we are looking for 24 | augmenting paths. 25 | */ 26 | 27 | // Initialising these as global variables to avoid passing as reference to every function 28 | vector graph; // to store the directed graph 29 | vector res_cap; // residual graph 30 | mii parent; // parent array to store parent of each vertex while doing bfs to backtrack on the augmenting path is found 31 | int n, m; // n = vertex_count, m = edge_count 32 | 33 | int bfs(int s, int t) { 34 | // resetting parent map 35 | parent.clear(); 36 | 37 | // queue to store the vertex & min flow discovered so far in the augmenting path 38 | queue q; 39 | q.push({s, INF}); 40 | 41 | while (!q.empty()) { 42 | int curr = q.front().first; 43 | int flow = q.front().second; 44 | q.pop(); 45 | 46 | for (int next : graph[curr]) { 47 | // If the node hasn't been visited yet and it's residual flow is greater than zero 48 | if (parent.find(next) == parent.end() && res_cap[curr][next] > 0) { 49 | // Add current node as parent of the next node 50 | parent[next] = curr; 51 | // Finding the minimum flow in the augmenting path 52 | int new_flow = min(flow, res_cap[curr][next]); 53 | // If sink is reached, that means the augmenting path has been found so return the min flow. 54 | if (next == t) return new_flow; 55 | // If the next node is not sink, then add it to queue for bfs. 56 | q.push({next, new_flow}); 57 | } 58 | } 59 | } 60 | 61 | // if no augmenting path found return flow as 0 to stop loop 62 | return 0; 63 | } 64 | 65 | int edmonds_karp_algo(int s, int t) { 66 | int max_flow = 0; // to store the final result (maximum flow possible) 67 | int flow; // to store the intermediate flows of augmenting paths 68 | 69 | while (flow = bfs(s, t)) { 70 | max_flow += flow; // increment the result 71 | 72 | // Traversing through the augmenting path by backtracking the parent map 73 | int curr = t; 74 | while (curr != s) { 75 | int prev = parent[curr]; // previous is parent of current vertex 76 | res_cap[prev][curr] -= flow; // Subtract the min flow from the direct edges in the path 77 | res_cap[curr][prev] += flow; // Add the min flow to the opposite edges in the path 78 | curr = prev; 79 | } 80 | } 81 | 82 | return max_flow; 83 | } 84 | 85 | int main() { 86 | cin >> n >> m; 87 | graph.resize(n); 88 | res_cap.resize(n); 89 | for (int i = 0; i < n; i++) res_cap[i].resize(n); 90 | for (int i = 0; i < n; i++) { 91 | for (int j = 0; j < n; j++) { 92 | res_cap[i][j] = 0; 93 | } 94 | } 95 | 96 | // vertices are 0-based 97 | for (int i = 0; i < m; i++) { 98 | int u, v, capacity; 99 | cin >> u >> v >> capacity; 100 | graph[u].pb(v); 101 | graph[v].pb(u); 102 | res_cap[u][v] = capacity; 103 | } 104 | 105 | int s, t; // s = source vertex & t = sink vertex in the network 106 | cin >> s >> t; 107 | cout << "Max flow possible in the network = " << edmonds_karp_algo(s, t) << "\n"; 108 | 109 | return 0; 110 | } 111 | 112 | /* 113 | Sample i/p ----> 114 | 6 9 115 | 0 1 7 116 | 0 4 4 117 | 1 2 5 118 | 1 3 3 119 | 2 5 8 120 | 3 2 3 121 | 3 5 5 122 | 4 3 2 123 | 4 1 3 124 | 0 5 125 | Sample o/p ----> 126 | Max flow possible in the network = 10 127 | */ -------------------------------------------------------------------------------- /Graphs/Maximum_Flow/Ford-Fulkerson_Algorithm.txt: -------------------------------------------------------------------------------- 1 | # Algorithm 2 | Step 1. Initialize flow through each edge = 0. 3 | Step 2. Initialize max_flow = 0. 4 | Step 3. while(there is an augmenting path from source(s) to sink(t) in the residual network graph(whether in 5 | residual graph or reverse residual graph or combined) 6 | { 7 | 1. find 'f', the minimum edge weight along the path. 8 | 2. update the edges of graph in Step 1 accordingly. 9 | 3. decrease capacity of all edges of the path in the residual graph by f. 10 | 4. increase capacity of all edges of the path in the reverse residual graph by f. 11 | 5. max_flow += f 12 | } 13 | 14 | # It should be noted, that the Ford-Fulkerson method doesn't specify a method of finding the augmenting path. 15 | 16 | # Possible approaches are using DFS or BFS which both work in O(E). If all capacities of the network are integers, 17 | then for each augmenting path the flow of the network increases by at least 1 (for more details see Integral flow 18 | theorem). 19 | 20 | # Therefore the complexity of Ford-Fulkerson is O(EF), where F is the maximal flow of the network, thus the time complexity will be large if the max flow is a big number. 21 | In case of rational capacities, the algorithm will also terminate, but the complexity is not bounded. 22 | In case of irrational capacities, the algorithm might never terminate, and might not even converge to the 23 | maximal flow. 24 | 25 | -------------------------------------------------------------------------------- /Graphs/Maximum_Flow/introduction.txt: -------------------------------------------------------------------------------- 1 | # A 𝒏𝒆𝒕𝒘𝒐𝒓𝒌 is a 𝒅𝒊𝒓𝒆𝒄𝒕𝒆𝒅 𝒈𝒓𝒂𝒑𝒉 G with vertices V and edges E combined with a function c, which assigns each edge 2 | e ∈ E a non-negative integer value, the capacity of e. 3 | Such a network is called a 𝒇𝒍𝒐𝒘 𝒏𝒆𝒕𝒘𝒐𝒓𝒌, if we additionally label two vertices, one as 𝒔𝒐𝒖𝒓𝒄𝒆 and one as 𝒔𝒊𝒏𝒌. 4 | 5 | # A 𝒇𝒍𝒐𝒘 in a flow network is function f, that again assigns each edge e a non-negative integer value, namely the 6 | flow. The function has to fulfill the following two conditions: 7 | • The flow of an edge cannot exceed the capacity. 8 | • And the sum of the incoming flow of a vertex u has to be equal to the sum of the outgoing flow of u except 9 | in the source and sink vertices. The source vertex s only has an outgoing flow, and the sink vertex t has 10 | only incoming flow. And the sum of outflow of source must be = sum of inflow of sink. 11 | 12 | # Or we can say 𝒇𝒍𝒐𝒘 is the exact amount of material flowing through the edge. 13 | # While 𝒄𝒂𝒑𝒂𝒄𝒊𝒕𝒚 is the maximum amount of material that can flow through the edge. 14 | 15 | # 𝑹𝒆𝒔𝒊𝒅𝒖𝒂𝒍 𝒄𝒂𝒑𝒂𝒄𝒊𝒕𝒚 = capacity - flow (for an edge). 16 | # 𝑹𝒆𝒗𝒆𝒓𝒔𝒆 𝒆𝒅𝒈𝒆 𝒓𝒆𝒔𝒊𝒅𝒖𝒂𝒍 𝒄𝒂𝒑𝒂𝒄𝒊𝒕𝒚 = • Remember "reverse edge is always IMAGINARY" i.e. for edge (u, v), we 17 | assume an imaginary reverse edge (v, u) (even if there actually exists an edge from (v, u) in the graph, we don't 18 | take the graph's original (v, u) edge as reverse edge, but assume some imaginary edge (v, u) as reverse edge. 19 | 20 | • Residual capacity of reverse edge = capacity of reverse edge - flow in reverse edge. 21 | • If flow of edge (u, v) = x, then flow of reverse edge (v, u) is taken as -x. 22 | • Capacity of reverse edge (v, u) is taken as 0. 23 | 24 | # 𝑹𝒆𝒔𝒊𝒅𝒖𝒂𝒍 𝒈𝒓𝒂𝒑𝒉 = A graph represented with the help of it's residual edges. 25 | 26 | # So basically Residual capacity signifies "How much still can be send through the the pipe(edge)". 27 | And Reverse residual capacity signifies "By how much amount you can decrease the flow through the pipe(edge)". 28 | 29 | # 𝑨𝒖𝒈𝒎𝒆𝒏𝒕𝒆𝒅 𝒑𝒂𝒕𝒉 = A path from source to sink such that the residual capacity on every edge of the path > 0. 30 | 31 | # 𝑴𝒂𝒙𝒊𝒎𝒖𝒎 𝑭𝒍𝒐𝒘 = It is defined as the maximum amount of flow that the network would allow to flow from source 32 | to sink. 33 | 34 | # 2 algorithms to find out Maximum flow in a network(There are more): 35 | • Ford-Fulkerson algorithm. 36 | • Edmonds-Karp algorithm. -------------------------------------------------------------------------------- /Graphs/Minimum_Spanning_Tree/introduction.txt: -------------------------------------------------------------------------------- 1 | # Spanning Tree - it is a subset of Graph G (a tree), which has 𝑨𝑳𝑳 the vertices covered with 𝑴𝑰𝑵𝑰𝑴𝑼𝑴 2 | possible number of edges. Hence, a spanning tree does not have cycles and it cannot be disconnected (as it is a tree). 3 | 4 | # By the above definition, we can draw a conclusion that every connected and undirected Graph G has at least 5 | one spanning tree. 6 | 7 | # 𝑨 𝒅𝒊𝒔𝒄𝒐𝒏𝒏𝒆𝒄𝒕𝒆𝒅 𝒈𝒓𝒂𝒑𝒉 𝒅𝒐𝒆𝒔 𝒏𝒐𝒕 𝒉𝒂𝒗𝒆 𝒂𝒏𝒚 𝒔𝒑𝒂𝒏𝒏𝒊𝒏𝒈 𝒕𝒓𝒆𝒆, 𝒂𝒔 𝒊𝒕 𝒄𝒂𝒏𝒏𝒐𝒕 𝒃𝒆 𝒔𝒑𝒂𝒏𝒏𝒆𝒅 𝒕𝒐 𝒂𝒍𝒍 𝒊𝒕𝒔 𝒗𝒆𝒓𝒕𝒊𝒄𝒆𝒔. 8 | 9 | # A complete undirected graph can have maximum n⁽ⁿ⁻²⁾ number of spanning trees, where n is the number of nodes. 10 | 11 | # GENERAL PROPERTIES OF SPANNING TREE ⟶ 12 | • A connected graph G can have more than one spanning tree. 13 | • All possible spanning trees of graph G, have the same number of edges and vertices. 14 | • The spanning tree does not have any cycle (loops). 15 | • Removing one edge from the spanning tree will make the graph disconnected, i.e. the spanning tree is 16 | 𝒎𝒊𝒏𝒊𝒎𝒂𝒍𝒍𝒚 𝒄𝒐𝒏𝒏𝒆𝒄𝒕𝒆𝒅 (i.e. if the spanning tree has 'n' vertices then it will have exactly (n-1) edges). 17 | • Adding one edge to the spanning tree will create a circuit or loop, i.e. the spanning tree is 𝒎𝒂𝒙𝒊𝒎𝒂𝒍𝒍𝒚 𝒂𝒄𝒚𝒄𝒍𝒊𝒄. 18 | 19 | # MATHEMATICAL PROPERTIES OF SPANNING TREE ⟶ 20 | • Spanning tree has n-1 edges, where n is the number of nodes (vertices). 21 | • From a complete undirected graph graph, by removing maximum (e - n + 1) edges, we can construct a spanning tree. 22 | • A complete undirected graph can have maximum n⁽ⁿ⁻²⁾ number of spanning trees. 23 | 24 | # APPLICATION OF SPANNING TREE ⟶ 25 | • Spanning tree is basically used to find a minimum path to connect all nodes in a graph. 26 | Common application of spanning trees are − 27 | 1. Civil Network Planning 28 | 2. Computer Network Routing Protocol 29 | 3. Cluster Analysis 30 | 31 | # MINIMUM SPANNING TREE (MST) ⟶ 32 | • In a WEIGHTED graph, a minimum spanning tree is a spanning tree that has 𝑴𝑰𝑵𝑰𝑴𝑼𝑴 weight than all other 33 | spanning trees of the same graph. 34 | • In real-world situations, this weight can be measured as distance, congestion, traffic load or any arbitrary 35 | value denoted to the edges. 36 | • Minimum spanning tree may or may not be unique. 37 | If the weight assign for all the edges of graph are unique, then minimum spanning tree will be unique. 38 | Otherwise there can be many minimum spanning tree. 39 | 40 | # Algorithms used for finding MST for UG ⟶ 41 | • Kruskal's Algorithm 42 | • Prim's Algorithm 43 | (𝑩𝒐𝒕𝒉 𝒂𝒓𝒆 𝒈𝒓𝒆𝒆𝒅𝒚 𝒂𝒍𝒈𝒐𝒓𝒊𝒕𝒉𝒎𝒔.) 44 | 45 | # Total number of Spanning Trees in a Graph: ---> 46 | https://www.geeksforgeeks.org/total-number-spanning-trees-graph/ 47 | 48 | # 𝑻𝒉𝒆 𝒆𝒒𝒖𝒊𝒗𝒂𝒍𝒆𝒏𝒕 𝒐𝒇 𝒂 𝒎𝒊𝒏𝒊𝒎𝒖𝒎 𝒔𝒑𝒂𝒏𝒏𝒊𝒏𝒈 𝒕𝒓𝒆𝒆 𝒊𝒏 𝒂 𝒅𝒊𝒓𝒆𝒄𝒕𝒆𝒅 𝒈𝒓𝒂𝒑𝒉 𝒊𝒔 𝒄𝒂𝒍𝒍𝒆𝒅 𝒂𝒏 𝒐𝒑𝒕𝒊𝒎𝒖𝒎 𝒃𝒓𝒂𝒏𝒄𝒉𝒊𝒏𝒈 𝒐𝒓 𝒂 49 | 𝒎𝒊𝒏𝒊𝒎𝒖𝒎-𝒄𝒐𝒔𝒕 𝒂𝒓𝒃𝒐𝒓𝒆𝒔𝒄𝒆𝒏𝒄𝒆. 𝑻𝒉𝒆 𝒄𝒍𝒂𝒔𝒔𝒊𝒄𝒂𝒍 𝒂𝒍𝒈𝒐𝒓𝒊𝒕𝒉𝒎 𝒇𝒐𝒓 𝒔𝒐𝒍𝒗𝒊𝒏𝒈 𝒕𝒉𝒊𝒔 𝒑𝒓𝒐𝒃𝒍𝒆𝒎 𝒊𝒔 𝒕𝒉𝒆 𝑪𝒉𝒖-𝑳𝒊𝒖/𝑬𝒅𝒎𝒐𝒏𝒅𝒔 𝒂𝒍𝒈𝒐𝒓𝒊𝒕𝒉𝒎. 50 | visit: https://stackoverflow.com/questions/21991823/finding-a-minimum-spanning-tree-on-a-directed-graph 51 | 52 | # Why Prim’s and Kruskal’s MST algorithm fails for Directed Graph? 53 | visit: https://www.geeksforgeeks.org/why-prims-and-kruskals-mst-algorithm-fails-for-directed-graph/ 54 | 55 | # MAXIMUM SPANNING TREE ⟶ It is a spanning tree with weight greater than or equal to the weight of every other 56 | spanning tree. 57 | Such a tree can be found with algorithms such as Prim's or Kruskal's after multiplying the edge weights by -1 58 | and solving the MST problem on the new graph. 59 | -------------------------------------------------------------------------------- /Graphs/Minimum_Spanning_Tree/kruskal.cpp: -------------------------------------------------------------------------------- 1 | // Problem: Minimum Spanning Tree 2 | // Contest: SPOJ - Partial 3 | // URL: https://www.spoj.com/problems/MST/ 4 | // Memory Limit: 1536 MB 5 | // Time Limit: 2000 ms 6 | // Author: Bihan Chakraborty 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | #define vi vector 13 | #define pb push_back 14 | #define pii pair 15 | #define mii map 16 | 17 | /* 18 | # Kruskal's algorithm to find the minimum cost spanning tree uses the greedy approach. 19 | 20 | # Performs better for sparse graphs. For dense graphs, check prim's algorithm. 21 | 22 | # Works only in undirected graphs. 23 | 24 | # Works with an edge list representation of the graph. 25 | 26 | # Uses dsu with path compression 27 | 28 | # Algorithm: 29 | Sort the edge list 30 | Loop through the edge list and add the edges to mst if the src and dest vertices of the edges don't have a common parent in the dsu. 31 | Union the src and dest vertices in the dsu. 32 | 33 | # Time complexity: O(ELogE + ELogV) | Space complexity: O(1) 34 | */ 35 | 36 | // Get function for DSU 37 | int Get(mii &parent, int a) { 38 | return parent[a] = parent[a] == a ? a : Get(parent, parent[a]); 39 | } 40 | 41 | // Union function for DSU 42 | void Union(mii &parent, mii &rank, int a, int b) { 43 | a = Get(parent, a); 44 | b = Get(parent, b); 45 | if (rank[a] == rank[b]) { 46 | rank[a]++; 47 | } 48 | if (rank[a] > rank[b]) { 49 | parent[b] = a; 50 | } else { 51 | parent[a] = b; 52 | } 53 | } 54 | 55 | // Helper function to sort in ascending order based on edge weights 56 | bool comp(vi &a, vi &b) { 57 | return a[2] < b[2]; 58 | } 59 | 60 | vector kurskal(vector &edges) { 61 | vector mst; 62 | mii parent, rank; 63 | 64 | // Sorting edges in ascending order of edge weights 65 | sort(edges.begin(), edges.end(), comp); 66 | 67 | // Initializing DSU 68 | for (auto edge : edges) { 69 | parent[edge[0]] = edge[0]; 70 | parent[edge[1]] = edge[1]; 71 | rank[edge[0]] = 0; 72 | rank[edge[1]] = 0; 73 | } 74 | 75 | // Performing union operations on disjoint edges and adding to mst array. We move from lowest to highest edge cost greedily since the edges array is sorted. 76 | for (auto edge : edges) { 77 | int x = Get(parent, edge[0]); 78 | int y = Get(parent, edge[1]); 79 | if (x == y) continue; 80 | Union(parent, rank, x, y); 81 | mst.pb(edge); 82 | } 83 | return mst; 84 | } 85 | 86 | void add_edge(vector &edges, int src, int dest, int weight) { 87 | edges.pb({src, dest, weight}); 88 | edges.pb({dest, src, weight}); 89 | } 90 | 91 | int main() { 92 | vector edges; 93 | add_edge(edges, 0, 1, 10); 94 | add_edge(edges, 0, 2, 6); 95 | add_edge(edges, 0, 3, 5); 96 | add_edge(edges, 1, 3, 15); 97 | add_edge(edges, 2, 3, 4); 98 | vector mst = kurskal(edges); 99 | int total_cost = 0; 100 | for (auto it : mst) { 101 | cout << "Src: " << it[0] << " Dest: " << it[1] << " Weight: " << it[2] << endl; 102 | total_cost += it[2]; 103 | } 104 | cout << "Total MST cost: " << total_cost << endl; 105 | return 0; 106 | } -------------------------------------------------------------------------------- /Graphs/Minimum_Spanning_Tree/prims.cpp: -------------------------------------------------------------------------------- 1 | // Problem: Minimum Spanning Tree 2 | // Contest: SPOJ - Partial 3 | // URL: https://www.spoj.com/problems/MST/ 4 | // Memory Limit: 1536 MB 5 | // Time Limit: 2000 ms 6 | // Author: Bihan Chakraborty 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | #define vi vector 13 | #define pb push_back 14 | #define pii pair 15 | #define mii map 16 | 17 | /* 18 | # Like Kruskal’s algorithm, Prim’s algorithm is also a Greedy algorithm. 19 | 20 | # Works only in undirected graphs. 21 | 22 | # Works with an vertex list representation of the graph. 23 | 24 | # While kruskal's algorithm is good for sparse graphs, prim's algorithm performs better for dense graphs. 25 | */ 26 | 27 | vector prims(const vector> &graph, int src, int n) { 28 | priority_queue, greater> pq; 29 | vector mst; 30 | 31 | // visited array to keep track of all the vertices which have been included in the MST Set so far 32 | vector visited(n + 1, false); 33 | 34 | // Adding a dummy edge from starting vertex 35 | pq.push({0, src, src}); // Edge -> {weight, start_vertex, end_vertex} 36 | 37 | while (!pq.empty()) { 38 | // extract the edge with minimum weight among all the active edges 39 | vi edge = pq.top(); 40 | pq.pop(); 41 | 42 | int wt = edge[0]; 43 | int from = edge[1]; 44 | int to = edge[2]; 45 | 46 | if (visited[to]) { 47 | // discard this edge 48 | continue; 49 | } 50 | 51 | mst.pb({from, to, wt}); // {start_vertex, end_vertex, weight} 52 | visited[to] = true; 53 | 54 | for (auto x : graph[to]) { 55 | if (!visited[x.first]) { 56 | pq.push({x.second, to, x.first}); 57 | } 58 | } 59 | } 60 | 61 | // Removing the dummy edge inserted at start 62 | mst.erase(mst.begin()); 63 | 64 | return mst; 65 | } 66 | 67 | void add_vertex(vector> &graph, int src, int dest, int weight) { 68 | graph[src].pb({dest, weight}); 69 | graph[dest].pb({src, weight}); 70 | } 71 | 72 | int main() { 73 | int n = 8; 74 | vector> graph(n + 1); 75 | add_vertex(graph, 0, 1, 10); 76 | add_vertex(graph, 0, 2, 6); 77 | add_vertex(graph, 0, 3, 5); 78 | add_vertex(graph, 1, 3, 15); 79 | add_vertex(graph, 2, 3, 4); 80 | vector mst = prims(graph, 1, n); 81 | int total_cost = 0; 82 | for (auto it : mst) { 83 | cout << "Src: " << it[0] << " Dest: " << it[1] << " Weight: " << it[2] << endl; 84 | total_cost += it[2]; 85 | } 86 | cout << "Total MST cost: " << total_cost << endl; 87 | return 0; 88 | } -------------------------------------------------------------------------------- /Graphs/Minimum_Spanning_Tree/second-mst-kruskal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | 10 | /* 11 | # Kruskal's algorithm to find the minimum cost spanning tree uses the greedy approach. 12 | 13 | # Performs better for sparse graphs. For dense graphs, check prim's algorithm. 14 | 15 | # Works only in undirected graphs. 16 | 17 | # Works with an edge list representation of the graph. 18 | 19 | # Uses dsu with path compression 20 | 21 | # Algorithm: 22 | Sort the edge list 23 | Find the mst using kruskal's algorithm 24 | Loop though the edge list and remove one edge from the edge list and again find the mst using Kruskal's algorithm and keep track of the minimum cost 25 | The minimum cost that is not equal to the cost of the actual mst is the cost of the second mst 26 | 27 | # Time complexity: O(E * (ELogE + ELogV)) | Space complexity: O(1) 28 | */ 29 | 30 | // Get function for DSU 31 | int Get(mii &parent, int a) { 32 | return parent[a] = parent[a] == a ? a : Get(parent, parent[a]); 33 | } 34 | 35 | // Union function for DSU 36 | void Union(mii &parent, mii &rank, int a, int b) { 37 | a = Get(parent, a); 38 | b = Get(parent, b); 39 | if (rank[a] == rank[b]) { 40 | rank[a]++; 41 | } 42 | if (rank[a] > rank[b]) { 43 | parent[b] = a; 44 | } else { 45 | parent[a] = b; 46 | } 47 | } 48 | 49 | // Helper function to sort in ascending order based on edge weights 50 | bool comp(vi &a, vi &b) { 51 | return a[2] < b[2]; 52 | } 53 | 54 | int calc_mst_cost(const vector &mst, int n) { 55 | int total_cost = 0; 56 | if (mst.size() != (n - 1)) return -1; 57 | for (auto it : mst) total_cost += it[2]; 58 | return total_cost; 59 | } 60 | 61 | vector kruskal(vector &edges) { 62 | vector mst; 63 | mii parent, rank; 64 | 65 | // Initializing DSU 66 | for (auto edge : edges) { 67 | parent[edge[0]] = edge[0]; 68 | parent[edge[1]] = edge[1]; 69 | rank[edge[0]] = 0; 70 | rank[edge[1]] = 0; 71 | } 72 | for (auto edge : edges) { 73 | int x = Get(parent, edge[0]); 74 | int y = Get(parent, edge[1]); 75 | if (x == y) continue; 76 | Union(parent, rank, x, y); 77 | mst.pb(edge); 78 | } 79 | return mst; 80 | } 81 | 82 | // Time complexity: O(ELogE + ELogV) | Space complexity: O(1) 83 | vector second_mst_kruskal(vector &edges, int n) { 84 | vector second_mst; 85 | int mst_cost = 0; 86 | int second_mst_cost = INT_MAX; // If no mst exists, then second mst will be INT_MAX 87 | 88 | // Sorting edges in ascending order of edge weights 89 | sort(edges.begin(), edges.end(), comp); 90 | 91 | mst_cost = calc_mst_cost(kruskal(edges), n); 92 | 93 | if (mst_cost == -1) return {}; 94 | 95 | for (int i = 0; i < edges.size(); i++) { 96 | vector edges_copy = edges; 97 | vi tmp_edge = edges_copy[i]; 98 | // Removing ith edge 99 | edges_copy.erase(edges_copy.begin() + i); 100 | // Removing opposite edge as the graph is bidirectional 101 | for (int j = 0; j < edges_copy.size(); j++) { 102 | if (edges_copy[j][0] == tmp_edge[1] && edges_copy[j][1] == tmp_edge[0] && edges_copy[j][2] == tmp_edge[2]) { 103 | edges_copy.erase(edges_copy.begin() + j); 104 | break; 105 | } 106 | } 107 | vector tmp_second_mst = kruskal(edges_copy); 108 | int tmp_cost = calc_mst_cost(tmp_second_mst, n); 109 | if (tmp_cost != -1) { 110 | if (tmp_cost < second_mst_cost && tmp_cost != mst_cost) { 111 | second_mst_cost = tmp_cost; 112 | second_mst = tmp_second_mst; 113 | } 114 | } 115 | edges_copy.clear(); 116 | tmp_second_mst.clear(); 117 | } 118 | return second_mst; 119 | } 120 | 121 | void add_edge(vector &edges, int src, int dest, int weight) { 122 | edges.pb({src, dest, weight}); 123 | edges.pb({dest, src, weight}); 124 | } 125 | 126 | int main() { 127 | int total_vertex_count = 6; 128 | vector edges; 129 | add_edge(edges, 0, 1, 13); 130 | add_edge(edges, 1, 2, 7); 131 | add_edge(edges, 2, 3, 2); 132 | add_edge(edges, 0, 3, 27); 133 | add_edge(edges, 1, 3, 28); 134 | add_edge(edges, 0, 4, 39); 135 | add_edge(edges, 3, 4, 34); 136 | add_edge(edges, 4, 5, 36); 137 | add_edge(edges, 3, 5, 14); 138 | add_edge(edges, 2, 5, 7); 139 | 140 | vector mst = second_mst_kruskal(edges, total_vertex_count); 141 | int total_cost = calc_mst_cost(mst, total_vertex_count); 142 | if (total_cost == -1) { 143 | cout << "No mst found"; 144 | } else { 145 | for (auto it : mst) { 146 | cout << "Src: " << it[0] << " Dest: " << it[1] << " Weight: " << it[2] << endl; 147 | } 148 | cout << "Total MST cost: " << total_cost << endl; 149 | } 150 | return 0; 151 | } 152 | -------------------------------------------------------------------------------- /Graphs/Shortest_Path/bellman_ford.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ll long long 6 | #define MOD 1000000007 7 | #define inf 1e18 8 | #define vi vector 9 | #define pii pair 10 | #define pb push_back 11 | #define mp make_pair 12 | #define printarr(arr, n) \ 13 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 14 | 15 | /* 16 | # It is a graph search algorithm that finds the shortest path between a given source vertex and all other 17 | vertices in the graph. This algorithm can be used on both weighted and unweighted graphs and also on 18 | DG & UG. 19 | 20 | # It is a DP based algorithm. 21 | 22 | # Like Dijkstra's shortest path algorithm, the Bellman-Ford algorithm is also guaranteed to find the 23 | shortest path in a graph. 24 | 25 | # Though it is slower than Dijkstra's algorithm (Time Complexity: O(V x log(E))), Bellman-Ford 26 | (Time Complexity: O(V x E) is capable of handling graphs that contain negative edge weights, so it is 27 | more versatile. 28 | 29 | # It is worth noting that if there exists a negative cycle in the graph, then there is no shortest path. 30 | As Going around the negative cycle an infinite number of times would continue to decrease the cost of the 31 | path (even though the path length is increasing). 32 | Because of this, Bellman-Ford can also detect negative cycles which is a useful feature. 33 | 34 | # An UG can be converted in a DG, and so if a UG contains a -ve weight edge, then basically we can say that 35 | it's a -ve weight cycle and hence no shortest path exists. 36 | 37 | # Simple algorithm ----> 38 | 1. Mark the dist[src] = 0 (from itself) 39 | and dist[all other vertices from src] = infinity 40 | 41 | 2. If we consider the #vertices = n and #edges = m 42 | then we just have to relax m edges (n-1) times for worst case. 43 | i.e. for(int i=1; i &edgeList, int src, int vertex_count, int edge_count) { 63 | vi dist(vertex_count, INT_MAX); 64 | dist[src] = 0; 65 | for (int i = 1; i < vertex_count; i++) { 66 | for (int j = 0; j < edge_count; j++) { 67 | int u = edgeList[j][0]; 68 | int v = edgeList[j][1]; 69 | int w = edgeList[j][2]; 70 | int newDistance = dist[u] + w; 71 | if (newDistance < dist[v]) { 72 | dist[v] = newDistance; 73 | } 74 | } 75 | } 76 | for (int j = 0; j < edge_count; j++) { 77 | int u = edgeList[j][0]; 78 | int v = edgeList[j][1]; 79 | int w = edgeList[j][2]; 80 | int newDistance = dist[u] + w; 81 | if (newDistance < dist[v]) { 82 | cout << "Negative cycle found between vertex " << u << " and " << v << endl; 83 | break; 84 | } 85 | } 86 | return dist; 87 | } 88 | 89 | int main() { 90 | int vertex_count = 5, edge_count = 8; 91 | // 0 indexed graph 92 | vector edgeList; 93 | // src, dest, weight 94 | edgeList.pb({0, 1, -1}); 95 | edgeList.pb({0, 2, 4}); 96 | edgeList.pb({1, 2, 3}); 97 | edgeList.pb({1, 3, 2}); 98 | edgeList.pb({1, 4, 2}); 99 | edgeList.pb({3, 2, 5}); 100 | edgeList.pb({3, 1, 1}); 101 | edgeList.pb({4, 3, -3}); 102 | vi dist = bellman_ford(edgeList, 0, vertex_count, edge_count); 103 | for (auto it : dist) cout << it << " "; 104 | return 0; 105 | } -------------------------------------------------------------------------------- /Graphs/Shortest_Path/dijkstra_multi_source_CP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ll long long 6 | #define MOD 1000000007 7 | #define inf 1e18 8 | #define vi vector 9 | #define pii pair 10 | #define pb push_back 11 | #define mp make_pair 12 | #define printarr(arr, n) \ 13 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 14 | 15 | /* 16 | # This algorithm is Greedy based. 17 | 18 | # This algorithm is used for finding the shortest path(as well as their costs) from multiple starting nodes to all 19 | other nodes in a weighted & UD/DG. 20 | 21 | # The edges of the graph can be unidirectional/bidirectional. 22 | 23 | # Dijkstra’s algorithm doesn’t work for graphs with -𝒗𝒆 𝒘𝒆𝒊𝒈𝒉𝒕 𝒄𝒚𝒄𝒍𝒆𝒔, it 𝑴𝑨𝒀 give correct results for a 24 | graph with -𝒗𝒆 𝒆𝒅𝒈𝒆𝒔. 25 | 26 | # For graphs with negative weight edges and cycles, 𝑩𝒆𝒍𝒍𝒎𝒂𝒏–𝑭𝒐𝒓𝒅 𝒂𝒍𝒈𝒐𝒓𝒊𝒕𝒉𝒎 can be used. 27 | 28 | # This algorithm basically creates trees of shortest paths from the starting vertices, to all 29 | other points in the graph. 30 | 31 | # Time Complexity: O(V x log(E)) 32 | */ 33 | 34 | pair multi_dijkstra(vector> &graph, vi src, int n) { 35 | set s; 36 | vi dist(n + 1, INT_MAX); 37 | vi prev(n + 1, -1); 38 | for (auto it : src) { 39 | dist[it] = 0; 40 | s.insert({0, it}); 41 | } 42 | while (!s.empty()) { 43 | // Popping the current min element from the set. First value of the pair isn't required as we can get it from the dist array. It is used in the set for getting the min index value 44 | int current = s.begin()->second; 45 | s.erase(s.begin()); 46 | // Iterating through the neighbours of current 47 | for (auto it : graph[current]) { 48 | // Index of a neighbour 49 | int adj_el = it.first; 50 | // Weight of the edge between current and the neighbour 51 | int weight = it.second; 52 | if (dist[current] + weight < dist[adj_el]) { 53 | // Updating the the shorter distance along with the vertex's index in the set 54 | s.erase({dist[adj_el], adj_el}); 55 | dist[adj_el] = dist[current] + weight; 56 | s.insert({dist[adj_el], adj_el}); 57 | // Creating parent-child relationship for traversing through the shortest route 58 | prev[adj_el] = current; 59 | } 60 | } 61 | } 62 | return {dist, prev}; 63 | } 64 | 65 | int main() { 66 | int n = 8; 67 | vector> graph(n + 1); 68 | graph[1].pb({2, 5}); 69 | graph[1].pb({8, 8}); 70 | graph[1].pb({5, 9}); 71 | graph[2].pb({4, 15}); 72 | graph[2].pb({3, 12}); 73 | graph[2].pb({8, 4}); 74 | graph[3].pb({4, 3}); 75 | graph[3].pb({7, 11}); 76 | graph[4].pb({7, 9}); 77 | graph[5].pb({8, 5}); 78 | graph[5].pb({6, 4}); 79 | graph[5].pb({7, 20}); 80 | graph[6].pb({3, 1}); 81 | graph[6].pb({7, 13}); 82 | graph[8].pb({3, 7}); 83 | graph[8].pb({6, 6}); 84 | 85 | vi sources = {1, 2}; 86 | pair ans = multi_dijkstra(graph, sources, n); 87 | cout << "Final minimum distances: "; 88 | for (auto it : ans.first) cout << it << " "; 89 | cout << endl; 90 | cout << "Shortest path from 7 to a source is: "; 91 | // Since the algorithm was ran with 1 as source, so we can get shortest path for all vertexes only from 1 92 | int target = 7; 93 | while (target != -1) { 94 | cout << target << " "; 95 | target = ans.second[target]; 96 | } 97 | return 0; 98 | } -------------------------------------------------------------------------------- /Graphs/Shortest_Path/dijkstra_single_source_CP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ll long long 6 | #define MOD 1000000007 7 | #define inf 1e18 8 | #define vi vector 9 | #define pii pair 10 | #define pb push_back 11 | #define mp make_pair 12 | #define printarr(arr, n) \ 13 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 14 | 15 | /* 16 | # This algorithm is Greedy based. 17 | 18 | # This algorithm is used for finding the shortest path(as well as their costs) from a starting node to all 19 | other nodes in a weighted & UD/DG. 20 | 21 | # The edges of the graph can be unidirectional/bidirectional. 22 | 23 | # Dijkstra’s algorithm doesn’t work for graphs with -𝒗𝒆 𝒘𝒆𝒊𝒈𝒉𝒕 𝒄𝒚𝒄𝒍𝒆𝒔, it 𝑴𝑨𝒀 give correct results for a 24 | graph with -𝒗𝒆 𝒆𝒅𝒈𝒆𝒔. 25 | 26 | # For graphs with negative weight edges and cycles, 𝑩𝒆𝒍𝒍𝒎𝒂𝒏–𝑭𝒐𝒓𝒅 𝒂𝒍𝒈𝒐𝒓𝒊𝒕𝒉𝒎 can be used. 27 | 28 | # This algorithm basically creates a tree of shortest paths from the starting vertex, the source, to all 29 | other points in the graph. 30 | 31 | # Time Complexity: O(V x log(E)) 32 | */ 33 | 34 | pair dijkstra(vector> &graph, int src, int n) { 35 | set s; 36 | vi dist(n + 1, INT_MAX); 37 | vi prev(n + 1, -1); 38 | dist[src] = 0; 39 | s.insert({0, src}); 40 | while (!s.empty()) { 41 | // Popping the current min element from the set. First value of the pair isn't required as we can get it from the dist array. It is used in the set for getting the min index value 42 | int current = s.begin()->second; 43 | s.erase(s.begin()); 44 | // Iterating through the neighbours of current 45 | for (auto it : graph[current]) { 46 | // Index of a neighbour 47 | int adj_el = it.first; 48 | // Weight of the edge between current and the neighbour 49 | int weight = it.second; 50 | if (dist[current] + weight < dist[adj_el]) { 51 | // Updating the the shorter distance along with the vertex's index in the set 52 | s.erase({dist[adj_el], adj_el}); 53 | dist[adj_el] = dist[current] + weight; 54 | s.insert({dist[adj_el], adj_el}); 55 | // Creating parent-child relationship for traversing through the shortest route 56 | prev[adj_el] = current; 57 | } 58 | } 59 | } 60 | return {dist, prev}; 61 | } 62 | 63 | int main() { 64 | int n = 8; 65 | vector> graph(n + 1); 66 | graph[1].pb({2, 5}); 67 | graph[1].pb({8, 8}); 68 | graph[1].pb({5, 9}); 69 | graph[2].pb({4, 15}); 70 | graph[2].pb({3, 12}); 71 | graph[2].pb({8, 4}); 72 | graph[3].pb({4, 3}); 73 | graph[3].pb({7, 11}); 74 | graph[4].pb({7, 9}); 75 | graph[5].pb({8, 5}); 76 | graph[5].pb({6, 4}); 77 | graph[5].pb({7, 20}); 78 | graph[6].pb({3, 1}); 79 | graph[6].pb({7, 13}); 80 | graph[8].pb({3, 7}); 81 | graph[8].pb({6, 6}); 82 | pair ans = dijkstra(graph, 1, n); 83 | cout << "Final minimum distances: "; 84 | for (auto it : ans.first) cout << it << " "; 85 | cout << endl; 86 | cout << "Shortest path from 1 to 7 is: "; 87 | // Since the algorithm was ran with 1 as source, so we can get shortest path for all vertexes only from 1 88 | int target = 7; 89 | while (target != -1) { 90 | cout << target << " "; 91 | target = ans.second[target]; 92 | } 93 | return 0; 94 | } -------------------------------------------------------------------------------- /Graphs/Shortest_Path/floyd-warshall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ll long long 6 | #define MOD 1000000007 7 | #define inf 1e18 8 | #define vi vector 9 | #define pii pair 10 | #define pb push_back 11 | #define mp make_pair 12 | #define printarr(arr, n) \ 13 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 14 | 15 | /* 16 | # As we need to find the shortest path from each node to all other nodes, it is better to represent the graph 17 | using adjacency matrix. 18 | 19 | # This algorithm is DP based as it breaks the problem down into smaller subproblems, then combines the 20 | answers to those subproblems to solve the big, initial problem. 21 | 22 | # The idea is this: either the quickest path from A to C is the quickest path found so far from A to C, or 23 | it's the quickest path from A to B plus the quickest path from B to C. 24 | 25 | # All pairs shortest path algorithm. 26 | 27 | # Works for weighted DG and UG. 28 | 29 | # Works with -ve edges as well. 30 | 31 | # Can detect -ve weight cycle, with one extra step in the main algorithm. 32 | * The graph has a negative cycle if at the end of the algorithm, the 33 | distance from a vertex v to itself is -ve. 34 | 35 | # Time complexity: O(V^3) | Space complexity: O(V^2) (Can be done with O(1) space by modifying the original graph) 36 | */ 37 | 38 | vector floyd_warshall(vector &adj_matrix) { 39 | vector dist = adj_matrix; 40 | for (int k = 0; k < dist.size(); k++) { 41 | for (int i = 0; i < dist.size(); i++) { 42 | for (int j = 0; j < dist.size(); j++) { 43 | if (dist[i][k] >= INT_MAX || dist[k][j] >= INT_MAX) continue; 44 | dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 45 | } 46 | } 47 | } 48 | for (int i = 0; i < dist.size(); i++) { 49 | if (dist[i][i] < 0) return {}; // Contains a negative cycle 50 | } 51 | return dist; 52 | } 53 | 54 | int main() { 55 | int vertex_count = 4; 56 | 57 | vector adj_matrix = {{0, 3, INT_MAX, 5}, 58 | {2, 0, INT_MAX, 8}, 59 | {INT_MAX, 1, 0, INT_MAX}, 60 | {INT_MAX, INT_MAX, 2, 0}}; 61 | 62 | vector dist = floyd_warshall(adj_matrix); 63 | for (int i = 0; i < vertex_count; i++) { 64 | for (int j = 0; j < vertex_count; j++) { 65 | cout << dist[i][j] << " "; 66 | } 67 | cout << endl; 68 | } 69 | for (int i = 0; i < vertex_count; i++) { 70 | for (int j = 0; j < vertex_count; j++) { 71 | cout << "Distance from " << i << " to " << j << " is " << dist[i][j] << endl; 72 | } 73 | } 74 | return 0; 75 | } -------------------------------------------------------------------------------- /Graphs/Shortest_Path/introduction.txt: -------------------------------------------------------------------------------- 1 | 2 | # Important points: 3 | Use BFS when no weights are associated with edges in the graph. 4 | Use Dijkstra when +ve weights are associated with edges in the graph. 5 | Use Bellman-Ford when -ve weights and -ve cycles associated with edges in the graph. 6 | 7 | # Time complexities: 8 | BFS: O(V+E) 9 | Dijkstra: O(V.log(E)) 10 | Bellman-Ford: O(V.E) 11 | Floyd-Warshall: O(V^3) -------------------------------------------------------------------------------- /Graphs/Strongly_Connected_Components/kosaraju_scc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | 10 | /* 11 | # Uses an adjacency vertex list. 12 | # Requires two Depth First Search Traversals. 13 | # Requires a stack. 14 | # Works on directed graphs as every undirected graph is a strongly connected component. 15 | # Algorithm: 16 | Sort the graph topologically and then transpose the graph. 17 | Pop vertices from the stack and run dfs on it if it is not already visited. 18 | Every dfs returns a strongly connected component. 19 | */ 20 | 21 | // Topological sort 22 | void dfs_1(const vector &graph, int src, vector &visited, stack &s) { 23 | visited[src] = true; 24 | for (int it : graph[src]) { 25 | if (!visited[it]) { 26 | dfs_1(graph, it, visited, s); 27 | } 28 | } 29 | s.push(src); 30 | } 31 | 32 | void dfs_2(const vector &graph, int src, vector &visited, vi &scc) { 33 | visited[src] = true; 34 | scc.pb(src); 35 | for (int it : graph[src]) { 36 | if (!visited[it]) { 37 | dfs_2(graph, it, visited, scc); 38 | } 39 | } 40 | } 41 | 42 | vector transpose_graph(const vector &graph) { 43 | vector tg(graph.size()); // Initializing transposed graph 44 | for (int i = 0; i < graph.size(); i++) { 45 | for (int j = 0; j < graph[i].size(); j++) { 46 | tg[graph[i][j]].pb(i); 47 | } 48 | } 49 | return tg; 50 | } 51 | 52 | // Time complexity: O() | Space complexity: O() 53 | vector kosaraju_scc(vector &graph) { 54 | stack s; 55 | vector visited(graph.size(), false); 56 | 57 | // Topologically sorting the graph and storing the result in stack s 58 | for (int i = 0; i < graph.size(); i++) { 59 | dfs_1(graph, 0, visited, s); 60 | } 61 | 62 | // Transposing the graph 63 | vector tg = transpose_graph(graph); 64 | 65 | // Resetting visited array for next dfs 66 | for (int i = 0; i < visited.size(); i++) visited[i] = false; 67 | 68 | // Initializing answer array 69 | vector total_scc; 70 | 71 | // Popping every vertex x from the stack and running dfs on it. Every vertex reachable from the vertex x together forms a scc. 72 | while (!s.empty()) { 73 | int top = s.top(); 74 | s.pop(); 75 | if (!visited[top]) { 76 | vi scc; 77 | dfs_2(tg, top, visited, scc); 78 | total_scc.pb(scc); 79 | } 80 | } 81 | return total_scc; 82 | } 83 | 84 | void add_vertex(vector &graph, int src, int dest) { 85 | graph[src].pb(dest); 86 | } 87 | 88 | int main() { 89 | int n = 5; 90 | vector graph(n + 1); 91 | add_vertex(graph, 1, 0); 92 | add_vertex(graph, 0, 2); 93 | add_vertex(graph, 2, 1); 94 | add_vertex(graph, 0, 3); 95 | add_vertex(graph, 3, 4); 96 | add_vertex(graph, 4, 3); 97 | vector scc = kosaraju_scc(graph); 98 | for (auto it : scc) { 99 | for (auto itt : it) { 100 | cout << itt << " "; 101 | } 102 | cout << endl; 103 | } 104 | return 0; 105 | } -------------------------------------------------------------------------------- /Graphs/Strongly_Connected_Components/tarjan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | 10 | /* 11 | # Uses an adjacency vertex list. 12 | # Requires a Depth First Search Traversal. 13 | # Requires a stack, two arrays for unique ids and low values of the vertices respectively. 14 | # Works on directed graphs as every undirected graph is a strongly connected component. 15 | */ 16 | 17 | void dfs(int curr, int &id, vector &graph, vi &ids, vi &low, vector &on_stack, stack &s) { 18 | // Adding vertex to stack 19 | s.push(curr); 20 | on_stack[curr] = true; 21 | 22 | // Assigning the vertex with an unique id thus marking it visited as well. The low value is also same here. 23 | ids[curr] = low[curr] = id++; 24 | 25 | for (auto to : graph[curr]) { 26 | // Visited neighbours if not already visited 27 | if (ids[to] == -1) dfs(to, id, graph, ids, low, on_stack, s); 28 | 29 | // After visiting the neighbour or if already visited, checking if it is in the stack. If so, we take the min of the current vertex and neightbour low value. 30 | // We are checking if the neighbour is in stack or not because if its not present in the stack, it can't be a part of curr's scc 31 | if (on_stack[to]) low[curr] = min(low[curr], low[to]); 32 | } 33 | 34 | // After visiting all neighbours, if the id and low value of current vertex is equal, that means its not a part of any other scc. Thus we pop all elements uptil curr vertex from the stack(curr included) since they can't be part of curr's scc. 35 | if (ids[curr] == low[curr]) { 36 | while (!s.empty()) { 37 | int node = s.top(); 38 | on_stack[node] = false; 39 | s.pop(); 40 | if (node == curr) break; 41 | } 42 | } 43 | } 44 | 45 | // Time complexity: O(V+E) | Space complexity: O(V) 46 | vector tarjan_scc(vector &graph, int n) { 47 | vector scc; 48 | // A counter variable to assign an incrementing unique id to all vertices. 49 | int id = 0; 50 | 51 | // ith element of the ids array will have an unique id once the ith vertex is visited. 52 | // ith element of the low array will have the id of the head vertex of the scc it is in. 53 | vi ids(n, -1), low(n, -1); 54 | 55 | // on_stack array to check whether a vertex is present in stack in O(1) 56 | vector on_stack(n, false); 57 | stack s; 58 | 59 | // Running dfs on each vertex 60 | for (int i = 0; i < n; i++) { 61 | if (ids[i] == -1) { 62 | dfs(i, id, graph, ids, low, on_stack, s); 63 | } 64 | } 65 | 66 | // Equal low values means that the vertices are of same scc. Here a hashmap is used to extract and categorise the data from low. 67 | map hash; 68 | for (int i = 0; i < n; i++) { 69 | hash[low[i]].pb(i); 70 | } 71 | for (auto it : hash) { 72 | scc.pb(it.second); 73 | } 74 | return scc; 75 | } 76 | 77 | void add_edge(vector &graph, int src, int dest) { 78 | graph[src].pb(dest); 79 | } 80 | 81 | int main() { 82 | int n = 8; 83 | vector graph(n); 84 | 85 | add_edge(graph, 6, 0); 86 | add_edge(graph, 6, 2); 87 | add_edge(graph, 3, 4); 88 | add_edge(graph, 6, 4); 89 | add_edge(graph, 2, 0); 90 | add_edge(graph, 0, 1); 91 | add_edge(graph, 4, 5); 92 | add_edge(graph, 5, 6); 93 | add_edge(graph, 3, 7); 94 | add_edge(graph, 7, 5); 95 | add_edge(graph, 1, 2); 96 | add_edge(graph, 7, 3); 97 | add_edge(graph, 5, 0); 98 | 99 | vector scc = tarjan_scc(graph, n); 100 | for (auto it : scc) { 101 | for (auto itt : it) { 102 | cout << itt << " "; 103 | } 104 | cout << endl; 105 | } 106 | return 0; 107 | } -------------------------------------------------------------------------------- /Graphs/Travelling_Salesman/tsp_dp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Start from a city and visit all the other cities and get back to the starting city with minimum total cost 12 | 13 | int n, startingCity, VISITED_ALL; 14 | 15 | // Time complexity: Without Memoization: O(n!), With Memoization: O(2^n . n) 16 | int tsp_dp(int currCity, int mask, const vector &adjMatrix, vector &dp) { 17 | // If all cities are visited, return distance from the current city to the starting city 18 | if (mask == VISITED_ALL) return adjMatrix[currCity][startingCity]; 19 | 20 | if (dp[currCity][mask] != -1) return dp[currCity][mask]; 21 | 22 | int ans = INT_MAX; 23 | 24 | // Looping through all cities connected with currCity in the adjMatrix 25 | for (int i = 0; i < n; i++) { 26 | // This binary number has one in the ith position, rest are 0 27 | int newMask = (1 << i); 28 | 29 | // The ith city is not visited yet 30 | if ((newMask & mask) == 0) { 31 | // We are marking the ith bit of mask as 1 by doing mask = mask | newMask 32 | ans = min(ans, adjMatrix[currCity][i] + tsp_dp(i, mask | newMask, adjMatrix, dp)); 33 | } 34 | } 35 | 36 | return dp[currCity][mask] = ans; 37 | } 38 | 39 | int main(int argc, char const *argv[]) { 40 | vector adjMatrix = {{0, 20, 42, 25}, {20, 0, 30, 34}, {42, 30, 0, 10}, {25, 34, 10, 0}}; 41 | n = adjMatrix.size(); 42 | 43 | // There are max n cities and the mask can contain a max of 2^n possible values (All permutations of 0 and 1 in binary number of size n) 44 | vector dp(n, vi((1 << n), -1)); 45 | 46 | // (1 << 4) = 2^4 = 16, binary: 10000, so (1 << 4) - 1 = 15, binary: 1111 47 | // Each bit represents a city, if all bits are one, then all cities are visited, else the 0 bit cities are yet to be visited 48 | VISITED_ALL = (1 << n) - 1; 49 | startingCity = 0; 50 | // Marking the bit corresponding to the starting city as 1 i.e. visited 51 | int mask = (1 << startingCity); 52 | int ans = tsp_dp(startingCity, mask, adjMatrix, dp); 53 | cout << ans << endl; 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /Graphs/cycle_detection_dfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | /* 6 | # Depth First Search Traversal to detect cycles. 7 | # Requires a stack. 8 | # The edges of the graph can be unidirectional/bidirectional. 9 | # Time complexity: O(V + E) | Space complexity: O(V) 10 | */ 11 | 12 | class Vertex { 13 | public: 14 | string data; 15 | vector neighbours; 16 | Vertex(string val) { 17 | data = val; 18 | } 19 | }; 20 | 21 | class Graph { 22 | private: 23 | vector vertexList; 24 | 25 | public: 26 | void addVertex(string data) { 27 | vertexList.push_back(Vertex(data)); 28 | } 29 | void set_edge(int u, int v) { 30 | vertexList[u].neighbours.push_back(v); 31 | } 32 | void dfs(int start, vector &visiting, vector &visited) { 33 | visiting[start] = true; 34 | visited[start] = true; 35 | for (int x : vertexList[start].neighbours) { 36 | if (visiting[x] == true) { 37 | cout << "Cycle found between " << vertexList[start].data << " and " << vertexList[x].data << endl; 38 | return; 39 | } 40 | if (!visited[x]) { 41 | dfs(x, visiting, visited); 42 | } 43 | } 44 | visiting[start] = false; 45 | } 46 | void find_cycles() { 47 | vector visiting(vertexList.size(), false); 48 | vector visited(vertexList.size(), false); 49 | for (int i = 0; i < vertexList.size(); i++) { 50 | if (!visited[i]) { 51 | dfs(i, visiting, visited); 52 | } 53 | } 54 | visiting.clear(); 55 | visited.clear(); 56 | } 57 | }; 58 | 59 | int main() { 60 | Graph g; 61 | g.addVertex("A"); // 0 62 | g.addVertex("B"); // 1 63 | g.addVertex("C"); // 2 64 | g.addVertex("D"); // 3 65 | g.addVertex("E"); // 4 66 | g.addVertex("F"); // 5 67 | g.set_edge(0, 1); 68 | g.set_edge(0, 2); 69 | g.set_edge(1, 2); 70 | g.set_edge(3, 0); 71 | g.set_edge(3, 4); 72 | g.set_edge(4, 5); 73 | g.set_edge(5, 3); // Makes the cycle 74 | g.find_cycles(); 75 | return 0; 76 | } -------------------------------------------------------------------------------- /Graphs/graph_bipartite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | /* 12 | 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 13 | vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. 14 | Equivalently, a bipartite graph is a graph that does not contain any odd-length cycles. 15 | We can check for odd cycles by putting colors to vertices. We use two colors and put one in each vertex such that no two adjacent vertices will have 16 | the same color. 17 | */ 18 | 19 | // Time complexity: O(n) | Space complexity: O(n) 20 | bool dfs(int curr, const vector &graph, vi &visited, vi &colors) { 21 | visited[curr] = true; 22 | for (int neighbour : graph[curr]) { 23 | // If two adjacent vertices have the same color and they are not the initial colors, then the graph isn't bipartite 24 | if (colors[neighbour] == colors[curr] && colors[curr] != 0) return false; 25 | if (!visited[neighbour]) { 26 | // Put the opposite color to the neighbour and continue dfs with it 27 | colors[neighbour] = colors[curr] == 1 ? 2 : 1; 28 | bool res = dfs(neighbour, graph, visited, colors); 29 | // If we get false from any neighbour's recursive function, we return false 30 | if (!res) return false; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | int main(int argc, char const *argv[]) { 37 | int n, m; 38 | cin >> n >> m; 39 | vector graph(n + 1); 40 | // we put color: 0 as the for all vertices(represents no color initially). While traversing we use colors 1 and 2 41 | vi visited(n + 1, false), colors(n + 1, 0); 42 | for (int i = 0; i < m; i++) { 43 | int u, v; 44 | cin >> u >> v; 45 | graph[u].pb(v); 46 | graph[v].pb(u); 47 | } 48 | int startingVertex = 1; 49 | // We mark the color of the starting vertex as 2. It can be 1 as well, doesn't matter 50 | colors[startingVertex] = 2; 51 | bool isBipartite = dfs(startingVertex, graph, visited, colors); 52 | if (isBipartite) { 53 | cout << "The graph is bipartite"; 54 | } else { 55 | cout << "The graph is not bipartite"; 56 | } 57 | cout << endl; 58 | return 0; 59 | } 60 | 61 | /* 62 | Input: 63 | 6 6 64 | 1 2 65 | 1 3 66 | 2 4 67 | 2 5 68 | 3 6 69 | 5 6 70 | Output: 71 | The graph is not bipartite 72 | 73 | Input: 74 | 6 5 75 | 1 2 76 | 2 4 77 | 2 5 78 | 3 6 79 | 5 6 80 | Output: 81 | The graph is bipartite 82 | */ 83 | -------------------------------------------------------------------------------- /Graphs/introduction.txt: -------------------------------------------------------------------------------- 1 | 2 | # Difference b/w Explicit Graph & Implicit Graph ------> 3 | • Explicit Graph: 4 | – All vertices are identified individually and represented separately. 5 | – All edges are identified individually and represented separately. 6 | 7 | • Implicit Graph: 8 | – Only a subset, possibly only one, of the vertices is given an explicit representation. (The others 9 | are implied.) or we can say it is a graph whose vertices or edges are not represented as explicit objects 10 | in a computer's memory, but rather are determined algorithmically from some more concise input. 11 | – Only a subset, and possibly zero, of the edges is given an explicit representation. 12 | – A set of “operators” is provided that can be used to construct “new” edges and vertices. 13 | 14 | 15 | # 𝑪𝒐𝒎𝒑𝒍𝒆𝒕𝒆 𝒈𝒓𝒂𝒑𝒉: it is a simple undirected graph in which every pair of distinct vertices is connected by a 16 | unique edge. 17 | # 𝑪𝒐𝒎𝒑𝒍𝒆𝒕𝒆 𝒅𝒊𝒈𝒓𝒂𝒑𝒉: it is a directed graph in which every pair of distinct vertices is connected by a pair of 18 | unique edges (one in each direction i.e. bi-directional edges). 19 | 20 | # 𝑺𝒊𝒎𝒑𝒍𝒆 𝒈𝒓𝒂𝒑𝒉: A graph which has neither self loops nor multiple edges(parallel edges.) i.e. where each edge 21 | connects two distinct vertices and no two edges connects the same pair of vertices is called a simple graph. 22 | # 𝑴𝒖𝒍𝒕𝒊𝒈𝒓𝒂𝒑𝒉: Any graph which contains some multiple edges is called a multigraph. In a multigraph, no self loops 23 | are allowed. 24 | # 𝑷𝒔𝒆𝒖𝒅𝒐 𝒈𝒓𝒂𝒑𝒉: A graph in which self loops and multiple edges are allowed is called psuedograph. -------------------------------------------------------------------------------- /Graphs/topological_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | /* Topological sort: 6 | # The edges of the graph can be unidirectional/bidirectional. 7 | # Requires a stack. 8 | # Run dfs on the graph and push each vertex in a stack after all its neighbours are visited. 9 | Pop each vertex from the stack and add it to a list to get the topologically sorted list of vertices. 10 | # Time complexity: O(V + E) | Space complexity: O(V) 11 | */ 12 | 13 | class Vertex { 14 | public: 15 | string data; 16 | vector neighbours; 17 | Vertex(string val) { 18 | data = val; 19 | } 20 | }; 21 | 22 | class Graph { 23 | private: 24 | vector vertexList; 25 | 26 | public: 27 | void addVertex(string data) { 28 | vertexList.push_back(Vertex(data)); 29 | } 30 | void set_edge(int u, int v) { 31 | vertexList[u].neighbours.push_back(v); 32 | } 33 | void dfs(int start, vector &visited, stack &s) { 34 | visited[start] = true; 35 | for (int x : vertexList[start].neighbours) { 36 | if (!visited[x]) { 37 | dfs(x, visited, s); 38 | } 39 | } 40 | s.push(start); 41 | } 42 | void topological_sort() { 43 | vector visited(vertexList.size(), false); 44 | stack s; 45 | for (int i = 0; i < vertexList.size(); i++) { 46 | if (!visited[i]) { 47 | dfs(i, visited, s); 48 | } 49 | } 50 | while (!s.empty()) { 51 | cout << vertexList[s.top()].data << " "; 52 | s.pop(); 53 | } 54 | visited.clear(); 55 | cout << endl; 56 | } 57 | }; 58 | 59 | int main() { 60 | Graph g; 61 | g.addVertex("A"); // 0 62 | g.addVertex("B"); // 1 63 | g.addVertex("C"); // 2 64 | g.addVertex("D"); // 3 65 | g.addVertex("E"); // 4 66 | g.addVertex("F"); // 5 67 | g.set_edge(2, 3); 68 | g.set_edge(3, 1); 69 | g.set_edge(4, 0); 70 | g.set_edge(4, 1); 71 | g.set_edge(5, 0); 72 | g.set_edge(5, 2); 73 | g.topological_sort(); 74 | return 0; 75 | } -------------------------------------------------------------------------------- /Greedy/README.md: -------------------------------------------------------------------------------- 1 | # Contains the solutions of the most common greedy problems. 2 | -------------------------------------------------------------------------------- /Greedy/activity_selection_problem.cpp: -------------------------------------------------------------------------------- 1 | // https://practice.geeksforgeeks.org/problems/activity-selection-1587115620/1 2 | #include 3 | using namespace std; 4 | 5 | class Solution { 6 | public: 7 | static bool comp(pair a, pair b) { 8 | if (a.second == b.second) return a.first < b.first; 9 | return a.second < b.second; 10 | } 11 | int activitySelection(vector start, vector end, int n) { 12 | vector> activities(n); 13 | for (int i = 0; i < n; i++) activities[i] = make_pair(start[i], end[i]); 14 | // Sort based on end time 15 | sort(activities.begin(), activities.end(), comp); 16 | int ans = 1; 17 | for (int i = 1, j = 0; i < n; i++) { 18 | if (activities[i].first > activities[j].second) { 19 | ans += 1; 20 | j = i; 21 | } 22 | } 23 | return ans; 24 | } 25 | }; 26 | 27 | int main() { 28 | int t; 29 | cin >> t; 30 | while (t--) { 31 | int n; 32 | cin >> n; 33 | vector start(n), end(n); 34 | for (int i = 0; i < n; i++) cin >> start[i]; 35 | for (int i = 0; i < n; i++) cin >> end[i]; 36 | Solution ob; 37 | cout << ob.activitySelection(start, end, n) << endl; 38 | } 39 | return 0; 40 | } 41 | 42 | /* 43 | Input: 44 | 1 45 | 4 46 | 1 3 2 5 47 | 2 4 3 6 48 | 49 | Output: 50 | 3 51 | */ -------------------------------------------------------------------------------- /Greedy/expedition_cows.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bihan001/Data-Structures-and-Algorithms/1e7ca989e5d5a77fdc6d60c4c96fa1efa2196be0/Greedy/expedition_cows.cpp -------------------------------------------------------------------------------- /Greedy/job_sequencing_dsu_nlogn.cpp: -------------------------------------------------------------------------------- 1 | // https://practice.geeksforgeeks.org/problems/job-sequencing-problem-1587115620/1 2 | #include 3 | using namespace std; 4 | 5 | struct Job { 6 | int id; // Job Id 7 | int dead; // Deadline of job 8 | int profit; // Profit if job is over before or on deadline 9 | }; 10 | 11 | class DSU { 12 | vector parent; 13 | 14 | public: 15 | DSU(int m) { 16 | parent.resize(m + 1); 17 | for (int i = 0; i <= m; i++) parent[i] = i; 18 | } 19 | int find(int n) { 20 | if (parent[n] == n) return n; 21 | return parent[n] = find(parent[n]); 22 | } 23 | void union_nodes(int u, int v) { parent[v] = u; } 24 | }; 25 | 26 | class Solution { 27 | public: 28 | static bool comp(Job a, Job b) { return a.profit > b.profit; } 29 | vector JobScheduling(Job arr[], int n) { 30 | int maxval = 0; 31 | for (int i = 0; i < n; i++) maxval = max(maxval, arr[i].dead); 32 | DSU d(maxval); 33 | int cnt = 0, profit = 0; 34 | // sort based on profit in descending order 35 | sort(arr, arr + n, comp); 36 | for (int i = 0; i < n; i++) { 37 | // Initially available slots will be their own deadline 38 | int availableSlot = d.find(arr[i].dead); 39 | // If availableSlot is greater than 0, then slots are available. 40 | // So we take that slot and union that with the next possible available slot which is currentSlot - 1. 41 | if (availableSlot > 0) { 42 | cnt += 1; 43 | profit += arr[i].profit; 44 | d.union_nodes(availableSlot - 1, availableSlot); 45 | } 46 | } 47 | return {cnt, profit}; 48 | } 49 | }; 50 | 51 | int main() { 52 | int t; 53 | cin >> t; 54 | while (t--) { 55 | int n; 56 | cin >> n; 57 | Job arr[n]; 58 | for (int i = 0; i < n; i++) { 59 | int x, y, z; 60 | cin >> x >> y >> z; 61 | arr[i].id = x; 62 | arr[i].dead = y; 63 | arr[i].profit = z; 64 | } 65 | Solution ob; 66 | vector ans = ob.JobScheduling(arr, n); 67 | cout << ans[0] << " " << ans[1] << endl; 68 | } 69 | return 0; 70 | } 71 | 72 | /* 73 | Input: 74 | 1 75 | 5 76 | 1 2 100 77 | 2 1 19 78 | 3 2 27 79 | 4 1 25 80 | 5 1 15 81 | 82 | Output: 83 | 2 127 84 | */ -------------------------------------------------------------------------------- /Greedy/job_sequencing_n2.cpp: -------------------------------------------------------------------------------- 1 | // https://practice.geeksforgeeks.org/problems/job-sequencing-problem-1587115620/1 2 | #include 3 | using namespace std; 4 | 5 | struct Job { 6 | int id; // Job Id 7 | int dead; // Deadline of job 8 | int profit; // Profit if job is over before or on deadline 9 | }; 10 | 11 | class Solution { 12 | public: 13 | static bool comp(Job a, Job b) { return a.profit > b.profit; } 14 | vector JobScheduling(Job arr[], int n) { 15 | int maxval = 0; 16 | for (int i = 0; i < n; i++) maxval = max(maxval, arr[i].dead); 17 | vector check(maxval, 0); 18 | int cnt = 0, profit = 0; 19 | // sort based on profit in descending order 20 | sort(arr, arr + n, comp); 21 | for (int i = 0; i < n; i++) { 22 | for (int j = min(arr[i].dead - 1, n - 1); j >= 0; j--) { 23 | if (!check[j]) { 24 | check[j] = 1; 25 | profit += arr[i].profit; 26 | cnt += 1; 27 | break; 28 | } 29 | } 30 | } 31 | return {cnt, profit}; 32 | } 33 | }; 34 | 35 | int main() { 36 | int t; 37 | cin >> t; 38 | while (t--) { 39 | int n; 40 | cin >> n; 41 | Job arr[n]; 42 | for (int i = 0; i < n; i++) { 43 | int x, y, z; 44 | cin >> x >> y >> z; 45 | arr[i].id = x; 46 | arr[i].dead = y; 47 | arr[i].profit = z; 48 | } 49 | Solution ob; 50 | vector ans = ob.JobScheduling(arr, n); 51 | cout << ans[0] << " " << ans[1] << endl; 52 | } 53 | return 0; 54 | } 55 | 56 | /* 57 | Input: 58 | 1 59 | 5 60 | 1 2 100 61 | 2 1 19 62 | 3 2 27 63 | 4 1 25 64 | 5 1 15 65 | 66 | Output: 67 | 2 127 68 | */ -------------------------------------------------------------------------------- /Linked List/linked_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | class Node { 6 | public: 7 | int data; 8 | Node *next; 9 | Node(int value) { 10 | data = value; 11 | next = NULL; 12 | } 13 | }; 14 | 15 | class LinkedList { 16 | private: 17 | Node *root; 18 | int size; 19 | 20 | public: 21 | LinkedList() { 22 | root = NULL; 23 | size = 0; 24 | } 25 | Node *insert_first(int data); 26 | Node *insert_end(int data); 27 | Node *insert_before(int pos, int data); 28 | Node *insert_after(int pos, int data); 29 | int remove_first(); 30 | int remove_end(); 31 | int remove_before(); 32 | int remove_after(); 33 | int remove_key(int key); 34 | int get_size(); 35 | void traverse(); 36 | }; 37 | 38 | Node *LinkedList::insert_first(int data) { 39 | Node *new_node = new Node(data); 40 | size += 1; 41 | if (root == NULL) { 42 | root = new_node; 43 | } else { 44 | new_node->next = root; 45 | root = new_node; 46 | } 47 | return new_node; 48 | } 49 | 50 | Node *LinkedList::insert_end(int data) { 51 | Node *new_node = new Node(data); 52 | size += 1; 53 | if (root == NULL) { 54 | root = new_node; 55 | } else { 56 | Node *p = root; 57 | while (p->next != NULL) p = p->next; 58 | p->next = new_node; 59 | } 60 | return new_node; 61 | } 62 | 63 | Node *LinkedList::insert_before(int pos, int data) { 64 | Node *new_node = new Node(data); 65 | size += 1; 66 | if (root == NULL) { 67 | root = new_node; 68 | } else { 69 | Node *current = root, *prev; 70 | for (int i = 0; i < pos; i++) { 71 | if (current) { 72 | prev = current; 73 | current = current->next; 74 | } else 75 | break; 76 | } 77 | if (prev) { 78 | new_node->next = prev->next; 79 | prev->next = new_node; 80 | } else { 81 | new_node->next = current; 82 | root = new_node; 83 | } 84 | } 85 | return new_node; 86 | } 87 | 88 | Node *LinkedList::insert_after(int pos, int data) { 89 | size -= 1; 90 | } 91 | 92 | int LinkedList::remove_first() { 93 | if (root == NULL) return -1; 94 | size -= 1; 95 | Node *p = root; 96 | root = root->next; 97 | int val = p->data; 98 | delete p; 99 | return val; 100 | } 101 | 102 | int LinkedList::remove_end() { 103 | if (root == NULL) return -1; 104 | size -= 1; 105 | Node *p = root; 106 | while (p->next->next != NULL) p = p->next; 107 | Node *t = p->next; 108 | int val = t->data; 109 | p->next = NULL; 110 | delete t; 111 | return val; 112 | } 113 | 114 | int LinkedList::remove_before() { 115 | size -= 1; 116 | } 117 | 118 | int LinkedList::remove_after() { 119 | size -= 1; 120 | } 121 | 122 | int LinkedList::remove_key(int key) { 123 | if (root == NULL) return -1; 124 | if (root->data == key) { 125 | int val = root->data; 126 | Node *t = root; 127 | root = root->next; 128 | delete t; 129 | size -= 1; 130 | return val; 131 | } 132 | Node *current = root, *prev = NULL; 133 | while (current && current->data != key) { 134 | prev = current; 135 | current = current->next; 136 | } 137 | if (!current) return -1; 138 | Node *t = current; 139 | int val = t->data; 140 | prev->next = current->next; 141 | delete t; 142 | size -= 1; 143 | return val; 144 | } 145 | 146 | int LinkedList::get_size() { 147 | return size; 148 | } 149 | 150 | void LinkedList::traverse() { 151 | Node *p = root; 152 | while (p != NULL) { 153 | cout << p->data << " "; 154 | p = p->next; 155 | } 156 | cout << endl; 157 | } 158 | 159 | int main(int argc, char const *argv[]) { 160 | LinkedList list1, list2; 161 | list1.insert_first(1); 162 | list1.insert_first(2); 163 | list1.insert_first(3); 164 | list1.remove_first(); 165 | list2.insert_first(4); 166 | list2.insert_first(5); 167 | list2.insert_first(6); 168 | list2.insert_before(1, 33); 169 | list1.traverse(); 170 | list2.traverse(); 171 | cout << list1.get_size() << endl; 172 | cout << list2.get_size() << endl; 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /Number Theory/count_and_sum_of_divisors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // If prime factorization of n is p1^e1 . p2^e2...pk^ek, then 6 | // d(n) = (e1+1) . (e2+1)...(ek+1) 7 | int divisors_count(int n) { 8 | map hash; 9 | while (n % 2 == 0) { 10 | hash[2]++; 11 | n = n / 2; 12 | } 13 | for (int i = 3; i <= sqrt(n); i += 2) { 14 | while (n % i == 0) { 15 | hash[i]++; 16 | n = n / i; 17 | } 18 | } 19 | if (n > 2) 20 | hash[n]++; 21 | 22 | int ans = 1; 23 | for (auto i : hash) { 24 | ans = ans * (i.second + 1); 25 | } 26 | return ans; 27 | } 28 | 29 | // If prime factorization of n is p1^e1 . p2^e2...pk^ek, then 30 | // σ(n) = (p1^(e1+1)-1)/(p1-1) . (p2^(e2+1)-1)/(p2-1) ... (pk^(ek+1)-1)/(pk-1) 31 | int sum_of_divisors(int n) { 32 | map hash; 33 | while (n % 2 == 0) { 34 | hash[2]++; 35 | n = n / 2; 36 | } 37 | for (int i = 3; i <= sqrt(n); i += 2) { 38 | while (n % i == 0) { 39 | hash[i]++; 40 | n = n / i; 41 | } 42 | } 43 | if (n > 2) 44 | hash[n]++; 45 | 46 | int sum = 1; 47 | for (auto i : hash) { 48 | sum = sum * (pow(i.first, i.second + 1) - 1) / (i.first - 1); 49 | } 50 | return sum; 51 | } 52 | 53 | int main() { 54 | cout << divisors_count(7) << " " << divisors_count(6) << " " << divisors_count(10) << endl; 55 | cout << sum_of_divisors(7) << " " << sum_of_divisors(6) << " " << sum_of_divisors(10); 56 | } -------------------------------------------------------------------------------- /Number Theory/euclidean_gcd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // O(log(min(a,b))) 6 | int gcd(int a, int b) { 7 | if (b == 0) 8 | return a; 9 | else 10 | return gcd(b, a % b); 11 | } 12 | 13 | int main() { 14 | cout << gcd(5, 6) << " " << gcd(24, 12); 15 | } -------------------------------------------------------------------------------- /Number Theory/euler_totient_function.cpp: -------------------------------------------------------------------------------- 1 | // Euler's totient function ϕ(n) counts the number of integers between 1 and n inclusive, which are coprime to n. 2 | // If n = p1^a1 . p2^a2 ... pk^ak, where p are the prime factors of n, ϕ(n) = n . (1 - 1/p1) . (1 - 1/p2) ...(1 - 1/pk) 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // O(sqrt(n)) 9 | int phi(int n) { 10 | int res = n; 11 | for (int i = 2; i * i <= n; i++) { 12 | if (n % i == 0) { 13 | while (n % i == 0) n = n / i; 14 | res = res - res / i; 15 | } 16 | } 17 | if (n > 1) res -= res / n; 18 | return res; 19 | } 20 | 21 | // O(n*log(loog n)) 22 | // To calculate phi(i) for range [1,n] 23 | vector phi_1_to_n(int n) { 24 | vector phi(n + 1); 25 | phi[0] = 0, phi[1] = 1; 26 | for (int i = 2; i <= n; i++) 27 | phi[i] = i; 28 | for (int i = 2; i <= n; i++) { 29 | if (phi[i] == i) { 30 | for (int j = i; j <= n; j += i) 31 | phi[j] -= phi[j] / i; 32 | } 33 | } 34 | return phi; 35 | } 36 | 37 | int main() { 38 | cout << phi(5) << " " << phi(6); 39 | cout << endl; 40 | vector phi = phi_1_to_n(10); 41 | for (auto &it : phi) cout << it << " "; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Number Theory/extended_euclidean_gcd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // O(log(min(a, b))) 6 | // (a . x) + (b ⋅ y) = gcd(a, b) 7 | // We are calculating x and y along with gcd(a, b) 8 | int gcd_extended(int a, int b, int *x, int *y) { 9 | if (a == 0) { 10 | *x = 0, *y = 1; 11 | return b; 12 | } 13 | int x1, y1; 14 | int gcd = gcd_extended(b % a, a, &x1, &y1); 15 | *x = y1 - (b / a) * x1; 16 | *y = x1; 17 | return gcd; 18 | } 19 | 20 | int main() { 21 | int x, y; 22 | int gcd = gcd_extended(55, 80, &x, &y); 23 | cout << gcd << " " << x << " " << y; 24 | } -------------------------------------------------------------------------------- /Number Theory/modular_exponentiation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int power(int a, int p, int m) { 6 | int res = 1; 7 | a = a % m; 8 | if (a == 0) return 0; 9 | while (p > 0) { 10 | if (p & 1) res = res * a % m; // if(p%2==1) 11 | p = p >> 1; // p = p/2 12 | a = (a * a) % m; 13 | } 14 | return res; 15 | } 16 | 17 | int main() { 18 | int a = 2, p = 5, m = 13; 19 | cout << power(a, p, m); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /Number Theory/modular_multiplicative_inverse.cpp: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | // O(n) 8 | // Finding x such that -> (a * x) % m ≡ 1 9 | // x exists only if gcd(a, m) = 1 i.e. they are coprime 10 | // Range of x is {0,1,2...,m-1} 11 | int mod_inverse_naive(int a, int m) { 12 | a = a % m; 13 | for (int i = 1; i < m; i++) { 14 | if ((a * i) % m == 1) { 15 | return i; 16 | } 17 | } 18 | return 0; 19 | } 20 | // O(log m) 21 | // Using extended Euclidean algorithm -> ax + by = gcd(a, b) 22 | // => ax + my = 1 as gcd(a,m) should be 1 23 | // => ax ≡ 1 (mod m) we can remove the 'my' as m % m = 0 24 | 25 | int mod_inverse_efficient(int a, int m) { 26 | int m0 = m, x = 1, y = 0; 27 | if (m == 1) return 0; 28 | while (a > 1) { 29 | // Basic Euclidean gcd algo 30 | int q = a / m; 31 | int t = m; 32 | m = a % m; 33 | a = t; 34 | // Updating x and y in extended Euclidean algo 35 | t = y; 36 | y = x - q * y; 37 | x = t; 38 | } 39 | if (x < 0) x += m0; 40 | return x; 41 | } 42 | 43 | int main() { 44 | int a = 3, m = 11; 45 | cout << mod_inverse_naive(a, m); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Number Theory/primality_test_fermat.cpp: -------------------------------------------------------------------------------- 1 | // Fermat's little theorem 2 | // If n is a prime number, then for every a, 1 < a < n-1, a^(n-1) ≡ 1 (mod n) => a^(n-1) % n = 1 3 | // Success rate of the primality check is not 100% 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Function to calculate (a^p)%m 9 | int power(int a, int p, int m) { 10 | int res = 1; 11 | a = a % m; 12 | if (a == 0) return 0; 13 | while (p > 0) { 14 | if (p & 1) res = res * a % m; // if(p%2==1) 15 | p = p >> 1; // p = p/2 16 | a = (a * a) % m; 17 | } 18 | return res; 19 | } 20 | 21 | // O(k*log(n)) 22 | bool is_prime(int n, int k) { 23 | if (n <= 1 || n == 4) return false; 24 | if (n <= 3) return true; 25 | while (k--) { 26 | int a = 2 + rand() % (n - 4); // For k times, we use a random number ranging [2,n-2] and perform gcd with n to check if its prime in case the fermat's algo fails 27 | if (__gcd(a, n) != 1) return false; 28 | if (power(a, n - 1, n) != 1) return false; 29 | } 30 | return true; 31 | } 32 | 33 | int main() { 34 | int k = 10; 35 | cout << is_prime(5, k) << " " << is_prime(101, k) << " " << is_prime(100, k); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Queue/queue_ll.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, data): 3 | self.data = data 4 | self.next = None 5 | 6 | 7 | class Queue: 8 | def __init__(self): 9 | self.size = 0 10 | self.front = None 11 | self.rear = None 12 | 13 | def __len__(self): 14 | return self.size 15 | 16 | def __str__(self): 17 | p = self.front 18 | arr = [] 19 | while p: 20 | arr.append(p.data) 21 | p = p.next 22 | return str(arr) 23 | 24 | def enqueue(self, item): 25 | new_node = Node(item) 26 | self.size = self.size + 1 27 | if not self.front: 28 | self.front = self.rear = new_node 29 | else: 30 | self.rear.next = new_node 31 | self.rear = new_node 32 | return new_node 33 | 34 | def dequeue(self): 35 | if not self.front: 36 | return None 37 | self.size = self.size - 1 38 | p = self.front 39 | self.front = self.front.next 40 | return p 41 | 42 | def traverse(self): 43 | p = self.front 44 | while p: 45 | print(p.data, end=' ') 46 | p = p.next 47 | print() 48 | 49 | def get_size(self): 50 | return self.size 51 | 52 | 53 | queue = Queue() 54 | 55 | queue.enqueue(1) 56 | queue.enqueue(2) 57 | queue.enqueue(3) 58 | print(queue) 59 | print(len(queue)) 60 | queue.dequeue() 61 | queue.dequeue() 62 | queue.dequeue() 63 | queue.dequeue() 64 | queue.enqueue(5) 65 | queue.traverse() 66 | print(queue.get_size()) 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Data Structures and Algorithms

2 | 3 |

Author: Bihan Chakraborty

4 | 5 |

Topics covered till now

6 |
    7 |
  • Linked List 8 |
  • Stack
  • 9 |
  • Queue
  • 10 |
  • BST
  • 11 |
  • Backtracking
  • 12 |
  • Greedy
  • 13 |
  • Dynamic Programming
  • 14 |
  • Trie
  • 15 |
  • Graph
  • 16 |
  • Searching
  • 17 |
  • Sort
  • 18 |
  • String
  • 19 |
  • Number Theory
  • 20 |
21 | -------------------------------------------------------------------------------- /Search/binary_search.py: -------------------------------------------------------------------------------- 1 | def binary_search(arr, key, l, h): 2 | if(l > h): 3 | return -1 4 | mid = (l+h) // 2 5 | if(key == arr[mid]): 6 | return mid 7 | if(key < arr[mid]): 8 | return binary_search(arr, key, l, mid - 1) 9 | else: 10 | return binary_search(arr, key, mid+1, h) 11 | 12 | 13 | arr = [2, 3, 5, 6, 4, 3, 5, 6, 64, 2, 221, 32, 1, 2] 14 | 15 | arr.sort() 16 | 17 | print(arr) 18 | 19 | print(binary_search(arr, 64, 0, len(arr))) 20 | -------------------------------------------------------------------------------- /Search/linear_search.py: -------------------------------------------------------------------------------- 1 | def linear_search(arr, key, i=0): 2 | if(i >= len(arr)): 3 | return -1 4 | if(arr[i] == key): 5 | return i 6 | return linear_search(arr, key, i+1) 7 | 8 | 9 | arr = [2, 3, 5, 6, 4, 3, 5, 6, 64, 2, 221, 32, 1, 2] 10 | 11 | print(linear_search(arr, 100)) 12 | print(linear_search(arr, 64)) 13 | -------------------------------------------------------------------------------- /Square Root Decomposition/number_of_distinct_elements_in_range_l_to_r.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | int main(int argc, char const *argv[]) { 12 | int n; 13 | cin >> n; 14 | vi arr(n); 15 | for (int i = 0; i < n; i++) cin >> arr[i]; 16 | mii occurences; 17 | vi nextOccIndices(n); 18 | for (int i = n - 1; i >= 0; i--) { 19 | if (occurences.find(arr[i]) == occurences.end()) { 20 | nextOccIndices[i] = n; 21 | } else { 22 | nextOccIndices[i] = occurences[arr[i]]; 23 | } 24 | occurences[arr[i]] = i; 25 | } 26 | int blockSize = ceil(sqrt(n)); 27 | vector> blocks(n / blockSize + 1, set()); 28 | for (int i = 0; i < n; i++) { 29 | blocks[i / blockSize].insert(nextOccIndices[i]); 30 | } 31 | int q; 32 | cin >> q; 33 | while (q--) { 34 | int option; 35 | cin >> option; 36 | // update 37 | if (option == 1) { 38 | } 39 | // print 40 | if (option == 2) { 41 | int l, r, cnt = 0; 42 | cin >> l >> r; 43 | int startBlock = l / blockSize, endBlock = r / blockSize; 44 | if (startBlock == endBlock) { 45 | for (int i = l; i <= r; i++) { 46 | if (nextOccIndices[i] > r) cnt += 1; 47 | } 48 | cout << cnt << endl; 49 | continue; 50 | } 51 | for (int i = l; i <= (startBlock + 1) * blockSize - 1; i++) { 52 | if (nextOccIndices[i] > r) cnt += 1; 53 | } 54 | for (int i = endBlock * blockSize; i <= r; i++) { 55 | if (nextOccIndices[i] > r) cnt += 1; 56 | } 57 | for (int i = startBlock + 1; i <= endBlock - 1; i++) { 58 | cnt += distance(blocks[i].upper_bound(r), blocks[i].end()); 59 | } 60 | cout << cnt << endl; 61 | continue; 62 | } 63 | } 64 | return 0; 65 | } 66 | 67 | /* 68 | Input: 69 | 5 70 | 1 1 2 1 3 71 | 3 72 | 2 0 4 73 | 2 1 3 74 | 2 2 4 75 | 76 | Output: 77 | 3 78 | 2 79 | 3 80 | */ -------------------------------------------------------------------------------- /Square Root Decomposition/number_of_elements_greater_than_k_in_the_range_l_to_r_and_update.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // You are given an array of n integers and q queries of 2 types. For type 1 query, take two inputs: index and value and update do arr[index] = value. 12 | // For type 2 query, take 3 inputs: l, r and k. Then print the number of integers in range (l, r) that is strictly greater than k. 13 | 14 | int main(int argc, char const *argv[]) { 15 | int n; 16 | cin >> n; 17 | vi arr(n); 18 | for (int i = 0; i < n; i++) cin >> arr[i]; 19 | 20 | // Size of each block 21 | int blockSize = ceil(sqrt(n)); 22 | 23 | vector> blocks(n / blockSize + 1, set()); 24 | 25 | for (int i = 0; i < n; i++) { 26 | blocks[i / blockSize].insert(arr[i]); 27 | } 28 | 29 | int q; 30 | cin >> q; 31 | while (q--) { 32 | int option; 33 | cin >> option; 34 | // update 35 | if (option == 1) { 36 | int index, value; 37 | cin >> index >> value; 38 | blocks[index / blockSize].erase(arr[index]); 39 | blocks[index / blockSize].insert(value); 40 | arr[index] = value; 41 | } 42 | // print 43 | if (option == 2) { 44 | int l, r, k; 45 | cin >> l >> r >> k; 46 | int startBlock = l / blockSize, endBlock = r / blockSize, cnt = 0; 47 | 48 | // Edge case 49 | if (startBlock == endBlock) { 50 | for (int i = l; i <= r; i++) { 51 | if (arr[i] > k) cnt += 1; 52 | } 53 | cout << cnt << endl; 54 | return; 55 | } 56 | 57 | // Cannot use set/sort/upper_bound here as the ordering would be different. As we are not considering the whole block, 58 | // we need to manually check the elements 59 | for (int i = l; i <= (startBlock + 1) * blockSize - 1; i++) { 60 | if (arr[i] > k) cnt += 1; 61 | } 62 | // Cannot use set/sort/upper_bound here as the ordering would be different. As we are not considering the whole block, 63 | // we need to manually check the elements 64 | for (int i = endBlock * blockSize; i <= r; i++) { 65 | if (arr[i] > k) cnt += 1; 66 | } 67 | // For the blocks in between, we take the number of elements starting from the number just greater than k to the end of the block 68 | for (int i = startBlock + 1; i <= endBlock - 1; i++) { 69 | cnt += distance(blocks[i].upper_bound(k), blocks[i].end()); 70 | } 71 | cout << cnt << endl; 72 | continue; 73 | } 74 | } 75 | return 0; 76 | } 77 | 78 | /* 79 | Input: 80 | 6 81 | 7 3 9 13 5 4 82 | 4 83 | 2 0 3 6 84 | 2 0 5 8 85 | 1 2 3 86 | 2 0 5 6 87 | 88 | Output: 89 | 3 90 | 2 91 | 2 92 | */ -------------------------------------------------------------------------------- /Square Root Decomposition/range_sum_point_update.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Given an array of n integers, perform two types of queries on it. 12 | // In query of type 1, take two integers as input, index and value. Replace the element of that index to the value. 13 | // In query of type 2, take two integers l and r. Print the sum of all elements in the range l to r (inclusive). 14 | 15 | int main(int argc, char const *argv[]) { 16 | int n; 17 | cin >> n; 18 | vi arr(n); 19 | for (int i = 0; i < n; i++) cin >> arr[i]; 20 | 21 | // Each block is of size ceil(sqrt(n)) 22 | int blockSize = ceil(sqrt(n)); 23 | vi blocks(n / blockSize + 1, 0); 24 | 25 | // (i / blockSize) gives the block index where the index i is belonging to. 26 | // We store the sum of all elements of a block to the corresponding block of the blocks array 27 | for (int i = 0; i < n; i++) { 28 | blocks[i / blockSize] += arr[i]; 29 | } 30 | 31 | int q; 32 | cin >> q; 33 | while (q--) { 34 | int option; 35 | cin >> option; 36 | // update query 37 | if (option == 1) { 38 | int index, value; 39 | cin >> index >> value; 40 | 41 | // we subtract the old value of the index from its block and add the new value to it 42 | blocks[index / blockSize] -= arr[index]; 43 | blocks[index / blockSize] += value; 44 | arr[index] = value; 45 | continue; 46 | } 47 | // print query 48 | if (option == 2) { 49 | int l, r; 50 | cin >> l >> r; 51 | 52 | // startBlock holds the index of the block in which l belongs, endBlock holds the index of the block in which r belongs 53 | int startBlock = l / blockSize, endBlock = r / blockSize, sum = 0; 54 | 55 | // edge case 56 | if (startBlock == endBlock) { 57 | for (int i = l; i <= r; i++) sum += arr[i]; 58 | cout << sum << endl; 59 | continue; 60 | } 61 | 62 | // sum of all elements starting from l to the end of starting block 63 | // Time complexity: O(blockSize) 64 | for (int i = l; i <= (startBlock + 1) * blockSize - 1; i++) sum += arr[i]; 65 | 66 | // sum of all elements starting from the first index ending block to r 67 | // Time complexity: O(blockSize) 68 | for (int i = endBlock * blockSize; i <= r; i++) sum += arr[i]; 69 | 70 | // sum of all blocks in between starting and ending block 71 | // Time complexity: O(blockSize) [Since, blockSize * blockSize = n (approx)] 72 | for (int i = startBlock + 1; i <= endBlock - 1; i++) sum += blocks[i]; 73 | 74 | cout << sum << endl; 75 | } 76 | } 77 | return 0; 78 | } 79 | 80 | /* 81 | Input: 82 | 10 83 | 1 2 3 4 5 6 7 8 9 10 84 | 4 85 | 1 3 100 86 | 2 1 9 87 | 1 7 4 88 | 2 0 9 89 | 90 | Output: 91 | 150 92 | 147 93 | */ -------------------------------------------------------------------------------- /Square Root Decomposition/range_sum_range_update.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Given an array of n integers, perform two types of queries on it. 12 | // In query of type 1, take three integers as input, l, r and value. Add 'value' to all elements in range [l, r]. 13 | // In query of type 2, take two integers l and r. Print the sum of all elements in range [l, r]. 14 | 15 | int main(int argc, char const *argv[]) { 16 | int n; 17 | cin >> n; 18 | vi arr(n); 19 | for (int i = 0; i < n; i++) cin >> arr[i]; 20 | 21 | // Each block is of size ceil(sqrt(n)) 22 | int blockSize = ceil(sqrt(n)); 23 | vi blocks(n / blockSize + 1, 0), lazy(n / blockSize + 1, 0); 24 | 25 | // (i / blockSize) gives the block index where the index i is belonging to. 26 | // We store the sum of all elements of a block to the corresponding block of the blocks array 27 | for (int i = 0; i < n; i++) { 28 | blocks[i / blockSize] += arr[i]; 29 | } 30 | 31 | int q; 32 | cin >> q; 33 | while (q--) { 34 | int option; 35 | cin >> option; 36 | // update query 37 | if (option == 1) { 38 | int l, r, val; 39 | cin >> l >> r >> val; 40 | // startBlock holds the index of the block in which l belongs, endBlock holds the index of the block in which r belongs 41 | int startBlock = l / blockSize, endBlock = r / blockSize; 42 | 43 | // Updating only the lazy value and not the actual range. 44 | // Time complexity: O(n/blockSize+1) 45 | for (int i = startBlock; i <= endBlock; i++) lazy[i] += val; 46 | } 47 | // print query 48 | if (option == 2) { 49 | int l, r; 50 | cin >> l >> r; 51 | 52 | // startBlock holds the index of the block in which l belongs, endBlock holds the index of the block in which r belongs 53 | int startBlock = l / blockSize, endBlock = r / blockSize, sum = 0; 54 | 55 | // edge case 56 | if (startBlock == endBlock) { 57 | for (int i = l; i <= r; i++) sum += arr[i] + lazy[startBlock]; 58 | cout << sum << endl; 59 | continue; 60 | } 61 | 62 | // sum of all elements starting from l to the end of starting block 63 | // Time complexity: O(blockSize) 64 | for (int i = l; i <= (startBlock + 1) * blockSize - 1; i++) sum += arr[i] + lazy[startBlock]; 65 | 66 | // sum of all elements starting from the first index ending block to r 67 | // Time complexity: O(blockSize) 68 | for (int i = endBlock * blockSize; i <= r; i++) sum += arr[i] + lazy[endBlock]; 69 | 70 | // sum of all blocks in between starting and ending block 71 | // Time complexity: O(blockSize) [Since, blockSize * blockSize = n (approx)] 72 | for (int i = startBlock + 1; i <= endBlock - 1; i++) sum += blocks[i] + (lazy[i] * blockSize); 73 | 74 | cout << sum << endl; 75 | } 76 | } 77 | return 0; 78 | } 79 | 80 | /* 81 | Input: 82 | 10 83 | 1 2 3 4 5 6 7 8 9 10 84 | 4 85 | 1 3 8 100 86 | 2 1 9 87 | 1 7 9 4 88 | 2 0 9 89 | 90 | Output: 91 | 954 92 | 1079 93 | */ -------------------------------------------------------------------------------- /Stack/next_greater_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Next greater elements on right side and left side 12 | // Time complexity: O(n) | Space complexity: O(n) 13 | int main(int argc, char const *argv[]) { 14 | int n; 15 | cin >> n; 16 | vi arr(n), resRight(n, -1), resLeft(n, -1); 17 | for (int i = 0; i < n; i++) cin >> arr[i]; 18 | stack s; 19 | // Calculating the resRight 20 | for (int i = n - 1; i >= 0; i--) { 21 | while (!s.empty() && arr[s.top()] <= arr[i]) s.pop(); 22 | if (!s.empty()) resRight[i] = arr[s.top()]; 23 | s.push(i); 24 | } 25 | for (int it : resRight) cout << it << ' '; 26 | cout << endl; 27 | while (!s.empty()) s.pop(); // Clearing the stack for resLeft calculation 28 | // Calculating the resLeft 29 | for (int i = 0; i < n; i++) { 30 | while (!s.empty() && arr[s.top()] <= arr[i]) s.pop(); 31 | if (!s.empty()) resLeft[i] = arr[s.top()]; 32 | s.push(i); 33 | } 34 | for (int it : resLeft) cout << it << ' '; 35 | cout << endl; 36 | return 0; 37 | } 38 | 39 | /* 40 | Input: 41 | 4 42 | 13 7 6 12 43 | 44 | Output: 45 | -1 12 12 -1 46 | -1 13 7 13 47 | */ -------------------------------------------------------------------------------- /Stack/next_smaller_element: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bihan001/Data-Structures-and-Algorithms/1e7ca989e5d5a77fdc6d60c4c96fa1efa2196be0/Stack/next_smaller_element -------------------------------------------------------------------------------- /Stack/next_smaller_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Next smaller elements on right side and left side 12 | // Time complexity: O(n) | Space complexity: O(n) 13 | int main(int argc, char const *argv[]) { 14 | int n; 15 | cin >> n; 16 | vi arr(n), resRight(n, -1), resLeft(n, -1); 17 | for (int i = 0; i < n; i++) cin >> arr[i]; 18 | stack s; 19 | // Calculating the resRight 20 | for (int i = n - 1; i >= 0; i--) { 21 | while (!s.empty() && arr[s.top()] >= arr[i]) s.pop(); 22 | if (!s.empty()) resRight[i] = arr[s.top()]; 23 | s.push(i); 24 | } 25 | for (int it : resRight) cout << it << ' '; 26 | cout << endl; 27 | while (!s.empty()) s.pop(); // Clearing the stack for resLeft calculation 28 | // Calculating the resLeft 29 | for (int i = 0; i < n; i++) { 30 | while (!s.empty() && arr[s.top()] >= arr[i]) s.pop(); 31 | if (!s.empty()) resLeft[i] = arr[s.top()]; 32 | s.push(i); 33 | } 34 | for (int it : resLeft) cout << it << ' '; 35 | cout << endl; 36 | return 0; 37 | } 38 | 39 | /* 40 | Input: 41 | 4 42 | 13 7 6 12 43 | 44 | Output: 45 | 7 6 -1 -1 46 | -1 -1 -1 6 47 | */ -------------------------------------------------------------------------------- /Stack/stack_ll.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, data): 3 | self.data = data 4 | self.prev = None 5 | 6 | 7 | class Stack: 8 | def __init__(self): 9 | self.size = 0 10 | self.top = None 11 | 12 | def __len__(self): 13 | return self.size 14 | 15 | def __str__(self): 16 | p = self.top 17 | arr = [] 18 | while p: 19 | arr.append(p.data) 20 | p = p.prev 21 | return str(arr) 22 | 23 | def push(self, item): 24 | new_node = Node(item) 25 | self.size = self.size + 1 26 | if not self.top: 27 | self.top = new_node 28 | else: 29 | p = self.top 30 | self.top = new_node 31 | self.top.prev = p 32 | return new_node 33 | 34 | def pop(self): 35 | if not self.top: 36 | return None 37 | else: 38 | self.size = self.size - 1 39 | p = self.top 40 | self.top = self.top.prev 41 | return p 42 | 43 | def traverse(self): 44 | p = self.top 45 | while p: 46 | print(p.data, end=' ') 47 | p = p.prev 48 | print() 49 | 50 | def get_size(self): 51 | return self.size 52 | 53 | 54 | stack = Stack() 55 | 56 | stack.push(1) 57 | stack.push(2) 58 | stack.push(3) 59 | stack.push(4) 60 | print(stack) 61 | stack.pop() 62 | stack.pop() 63 | print(stack) 64 | stack.pop() 65 | stack.pop() 66 | stack.pop() 67 | stack.traverse() 68 | print(len(stack)) 69 | -------------------------------------------------------------------------------- /Strings/kmp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | void calc_lps_array(string pat, int *lps) { 6 | int m = pat.length(); 7 | int len = 0; 8 | lps[0] = 0; 9 | int i = 1; 10 | while (i < m) { 11 | if (pat[i] == pat[len]) { 12 | lps[i++] = ++len; 13 | } else { 14 | if (len != 0) 15 | len = lps[len - 1]; 16 | else { 17 | lps[i] = 0; 18 | i++; 19 | } 20 | } 21 | } 22 | } 23 | 24 | vector kmp_search(string s, string pat) { 25 | vector res; 26 | int n = s.length(); 27 | int m = pat.length(); 28 | int lps[m]; 29 | calc_lps_array(pat, lps); 30 | int i = 0, j = 0; 31 | while (i < n) { 32 | if (s[i] == pat[j]) { 33 | i++; 34 | j++; 35 | } 36 | if (j == m) { 37 | res.push_back(i - j); 38 | j = lps[j - 1]; 39 | } else if (i < n && pat[j] != s[i]) { 40 | if (j != 0) 41 | j = lps[j - 1]; 42 | else 43 | i += 1; 44 | } 45 | } 46 | return res; 47 | } 48 | 49 | int main() { 50 | string s = "ABABDABACDABABCABAB"; 51 | string pat = "ABA"; 52 | vector res; 53 | res = kmp_search(s, pat); 54 | for (auto &it : res) cout << it << " "; 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Strings/problems/count_of_cyclic_permutation_xor_with_binary_string_0.cpp: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/count-of-cyclic-permutations-having-xor-with-other-binary-string-as-0/ 2 | #include 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | const int INF = 0x3f3f3f3f; 10 | const int mod = 1e9 + 7; 11 | 12 | vi createZArray(string s) { 13 | int n = s.length(), l = 0, r = 0; 14 | vi z(n, 0); 15 | for (int i = 1; i < n; i++) { 16 | if (i > r) { 17 | l = r = i; 18 | while (r < n && s[r] == s[r - l]) r++; 19 | z[i] = r - l; 20 | r--; 21 | } else { 22 | if (z[i - l] + i - 1 < r) { 23 | z[i] = z[i - l]; 24 | } else { 25 | l = i; 26 | while (r < n && s[r] == s[r - l]) r++; 27 | z[i] = r - l; 28 | r--; 29 | } 30 | } 31 | } 32 | return z; 33 | } 34 | 35 | int main(int argc, char const *argv[]) { 36 | string a, b; 37 | cin >> a >> b; 38 | string s = a + '$' + b + b; 39 | s.pop_back(); 40 | vi z = createZArray(s); 41 | int cnt = 0; 42 | for (int i = 0; i < z.size(); i++) { 43 | if (z[i] == a.length()) cnt += 1; 44 | } 45 | cout << cnt << endl; 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Strings/z-algo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | void create_z_array(string tot, vector &z) { 5 | int n = tot.length(); 6 | int l, r, k; 7 | l = r = 0; 8 | for (int i = 1; i < n; i++) { 9 | // normal case: when we need to match the current values with its prefixes 10 | if (i > r) { 11 | // Resetting the z-box 12 | l = r = i; 13 | // Increasing the width of the z-box by incrementing r 14 | while (r < n && tot[r] == tot[r - l]) r++; 15 | // (r - l) = length of the substring that is also the prefix 16 | z[i] = r - l; 17 | r--; 18 | } else { 19 | // optimizing case: when i is inside the z-box so we don't need to recalculate its values 20 | // k = corresponding position in the prefix 21 | k = i - l; 22 | // if the expected value exists inside the z-box 23 | if ((z[k] + i - 1) < r) z[i] = z[k]; 24 | // else we need to recalculate the values like the normal case 25 | else { 26 | l = i; 27 | while (r < n && tot[r] == tot[r - l]) r++; 28 | z[i] = r - l; 29 | r--; 30 | } 31 | } 32 | } 33 | } 34 | 35 | int main() { 36 | // 0, 6, 11 37 | string s = "ababbaababbaba"; 38 | string pat = "aba"; 39 | string tot = pat + "$" + s; 40 | vector z(tot.length()); 41 | create_z_array(tot, z); 42 | for (int i = pat.length() + 1; i < tot.length(); i++) cout << z[i] << " "; 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Trees/Binary_Search_Tree/bst.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Node { 5 | public: 6 | int data; 7 | Node* lchild; 8 | Node* rchild; 9 | Node(int val) { 10 | data = val; 11 | lchild = NULL; 12 | rchild = NULL; 13 | } 14 | }; 15 | 16 | class BST { 17 | private: 18 | Node* root; 19 | Node* empty(Node* p) { 20 | if (p == NULL) return NULL; 21 | empty(p->lchild); 22 | empty(p->rchild); 23 | delete p; 24 | return NULL; 25 | } 26 | 27 | Node* insert(Node* p, int data) { 28 | if (p == NULL) { 29 | p = new Node(data); 30 | return p; 31 | } 32 | if (data < p->data) { 33 | p->lchild = insert(p->lchild, data); 34 | } else if (data > p->data) { 35 | p->rchild = insert(p->rchild, data); 36 | } 37 | return p; 38 | } 39 | 40 | Node* findMin(Node* p) { 41 | if (p == NULL) return NULL; 42 | if (p->lchild == NULL) return p; 43 | return findMin(p->lchild); 44 | } 45 | 46 | Node* findMax(Node* p) { 47 | if (p == NULL) return NULL; 48 | if (p->rchild == NULL) return p; 49 | return findMax(p->rchild); 50 | } 51 | 52 | int height(Node* p) { 53 | if (p == NULL) return 0; 54 | int l = height(p->lchild); 55 | int h = height(p->rchild); 56 | return l > h ? l + 1 : h + 1; 57 | } 58 | 59 | Node* inorder_predecessor(Node* p) { 60 | if (p == NULL) return NULL; 61 | if (p->rchild) return inorder_predecessor(p->rchild); 62 | return p; 63 | } 64 | 65 | Node* inorder_successor(Node* p) { 66 | if (p == NULL) return NULL; 67 | if (p->lchild) return inorder_successor(p->lchild); 68 | return p; 69 | } 70 | 71 | Node* erase(Node* p, int key) { 72 | Node* q; 73 | if (p == NULL) return NULL; 74 | if (p->lchild == NULL && p->rchild == NULL) { 75 | if (p == root) root = NULL; 76 | delete (p); 77 | return NULL; 78 | } 79 | if (key < p->data) 80 | p->lchild = erase(p->lchild, key); 81 | else if (key > p->data) 82 | p->rchild = erase(p->rchild, key); 83 | if (height(p->lchild) > height(p->rchild)) { 84 | q = inorder_predecessor(p->lchild); 85 | p->data = q->data; 86 | p->lchild = erase(p->lchild, q->data); 87 | } else { 88 | q = inorder_successor(p->rchild); 89 | p->data = q->data; 90 | p->rchild = erase(p->rchild, q->data); 91 | } 92 | return p; 93 | } 94 | 95 | void preorder(Node* p) { 96 | if (p == NULL) return; 97 | cout << p->data << ' '; 98 | preorder(p->lchild); 99 | preorder(p->rchild); 100 | } 101 | 102 | void inorder(Node* p) { 103 | if (p == NULL) return; 104 | inorder(p->lchild); 105 | cout << p->data << ' '; 106 | inorder(p->rchild); 107 | } 108 | 109 | void postorder(Node* p) { 110 | if (p == NULL) return; 111 | postorder(p->lchild); 112 | postorder(p->rchild); 113 | cout << p->data << ' '; 114 | } 115 | 116 | Node* find(Node* p, int key) { 117 | if (p == NULL) return NULL; 118 | if (key < p->data) return find(p->lchild, key); 119 | if (key > p->data) return find(p->rchild, key); 120 | return p; 121 | } 122 | 123 | public: 124 | BST() { root = NULL; } 125 | 126 | ~BST() { root = empty(root); } 127 | 128 | void insert(int data) { root = insert(root, data); } 129 | 130 | void erase(int key) { root = erase(root, key); } 131 | 132 | void display_preorder() { 133 | preorder(root); 134 | cout << endl; 135 | } 136 | 137 | void display_inorder() { 138 | inorder(root); 139 | cout << endl; 140 | } 141 | 142 | void display_postorder() { 143 | postorder(root); 144 | cout << endl; 145 | } 146 | 147 | bool find(int key) { 148 | Node* p = find(root, key); 149 | return p != NULL ? true : false; 150 | } 151 | }; 152 | 153 | int main() { 154 | BST t; 155 | t.insert(20); 156 | t.insert(25); 157 | t.insert(15); 158 | t.insert(10); 159 | t.insert(30); 160 | t.display_inorder(); 161 | cout << "20 exists: " << t.find(20) << endl; 162 | t.erase(20); 163 | cout << "20 exists: " << t.find(20) << endl; 164 | t.display_preorder(); 165 | t.display_inorder(); 166 | t.display_postorder(); 167 | t.erase(25); 168 | t.display_inorder(); 169 | t.erase(30); 170 | t.display_preorder(); 171 | return 0; 172 | } -------------------------------------------------------------------------------- /Trees/min_node_of_subtree_dp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | // Find the minimum node in the subtree of all nodes in the given tree 12 | 13 | void dfs(int curr, int parent, vi &minNodes, const vector &graph) { 14 | minNodes[curr] = curr; 15 | 16 | for (int child : graph[curr]) { 17 | if (child != parent) { 18 | dfs(child, curr, minNodes, graph); 19 | minNodes[curr] = min(minNodes[curr], minNodes[child]); 20 | } 21 | } 22 | } 23 | 24 | int main(int argc, char const *argv[]) { 25 | int n; 26 | cin >> n; 27 | vector tree(n + 1); 28 | for (int i = 1; i <= n - 1; i++) { 29 | int u, v; 30 | cin >> u >> v; 31 | tree[u].pb(v); 32 | tree[v].pb(u); 33 | } 34 | vi minNodes(n + 1); 35 | dfs(1, 0, minNodes, tree); 36 | for (int i = 1; i <= n; i++) cout << "Node: " << i << " Subtree min node: " << minNodes[i] << endl; 37 | return 0; 38 | } 39 | 40 | /* 41 | 10 42 | 1 2 43 | 1 4 44 | 2 8 45 | 8 6 46 | 8 10 47 | 6 9 48 | 4 3 49 | 4 5 50 | 5 7 51 | */ -------------------------------------------------------------------------------- /Trie/problems/maximum_xor_of_two_array_elements.cpp: -------------------------------------------------------------------------------- 1 | // ? SOLVED https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array 2 | #include 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | const int INF = 0x3f3f3f3f; 10 | const int mod = 1e9 + 7; 11 | 12 | class Node { 13 | public: 14 | int value; // 0, 1 15 | vector children; // size: 2 16 | Node(int val) { 17 | value = val; 18 | children.resize(2, NULL); 19 | } 20 | }; 21 | 22 | class Trie { 23 | public: 24 | Node *root; 25 | Trie() { root = new Node(-1); } 26 | void insert(int num) { 27 | Node *p = root; 28 | // we check and insert all 32 bits(integer range) of each number so all numbers have the same bit count 29 | for (int i = 31; i >= 0; i--) { 30 | // starting from the msb(31) and moving to the lsb(0) 31 | int bit = (num >> i) & 1; // possible values: 0 and 1 32 | // we check if there is a node in the 0th or 1st index of the children array according to the bit. If not, we create it 33 | if (!p->children[bit]) p->children[bit] = new Node(bit); 34 | // then we move down the trie 35 | p = p->children[bit]; 36 | } 37 | } 38 | int findMaxXor(vi &arr) { 39 | int maxXor = INT_MIN; 40 | for (int num : arr) { 41 | int currXor = 0; 42 | Node *p = root; 43 | for (int i = 31; i >= 0; i--) { 44 | // for each number in the array, we check each of its 32 bits and find the opposite bit in the trie. If found we proceed with that, 45 | // else we take the same bit. We update our currXor whenever we proceed with the opposite bit as bit ^ oppositeBit = 1, 46 | // so pow(2,n)*1 = pow(2^n). If we proceed with the same bits then the result will be pow(2, n)*0 = 0; 47 | int bit = (num >> i) & 1; 48 | int invertedBit = !bit; 49 | if (p->children[invertedBit]) { 50 | p = p->children[invertedBit]; 51 | currXor += (1 << i); // (1 << i) == pow(2, i) 52 | } else { 53 | p = p->children[bit]; 54 | } 55 | } 56 | maxXor = max(maxXor, currXor); 57 | } 58 | return maxXor; 59 | } 60 | }; 61 | 62 | int main(int argc, char const *argv[]) { 63 | int n; 64 | cin >> n; 65 | vi arr(n); 66 | for (int i = 0; i < n; i++) { 67 | cin >> arr[i]; 68 | } 69 | Trie t; 70 | for (auto it : arr) t.insert(it); 71 | int ans = t.findMaxXor(arr); 72 | cout << ans << endl; 73 | return 0; 74 | } 75 | 76 | /* 77 | Input: 78 | 6 79 | 3 10 5 25 2 8 80 | 81 | Output: 82 | 28 83 | */ -------------------------------------------------------------------------------- /Trie/problems/shortest_unique_prefix_for_every_word.cpp: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/find-all-shortest-unique-prefixes-to-represent-each-word-in-a-given-list/ 2 | #include 3 | using namespace std; 4 | 5 | #define vi vector 6 | #define pb push_back 7 | #define pii pair 8 | #define mii map 9 | const int INF = 0x3f3f3f3f; 10 | const int mod = 1e9 + 7; 11 | 12 | class Node { 13 | public: 14 | char value; 15 | int count; 16 | bool isLeaf; 17 | map children; 18 | Node(char val) { 19 | value = val; 20 | count = 1; 21 | isLeaf = false; 22 | } 23 | }; 24 | 25 | class Trie { 26 | private: 27 | Node *root; 28 | int words; 29 | vector prefixes; 30 | void _insert(Node *root, string word) { 31 | if (!root) return; 32 | if (word == "") { 33 | root->isLeaf = true; 34 | words++; 35 | return; 36 | } 37 | char newChar = word[0]; 38 | string restWord = word.substr(1); 39 | if (root->children.find(newChar) == root->children.end()) { 40 | root->children[newChar] = new Node(newChar); 41 | } else { 42 | root->children[newChar]->count++; 43 | } 44 | _insert(root->children[newChar], restWord); 45 | } 46 | void _getUniquePrefixes(Node *root, string currWord) { 47 | if (!root) return; 48 | if (root->count == 1) { 49 | prefixes.pb(currWord + root->value); 50 | return; 51 | } 52 | for (auto it : root->children) { 53 | _getUniquePrefixes(it.second, currWord + root->value); 54 | } 55 | } 56 | 57 | public: 58 | Trie() { 59 | root = new Node('\0'); 60 | root->count = 0; 61 | words = 0; 62 | } 63 | void insert(string word) { _insert(root, word); } 64 | 65 | vector getUniquePrefixes() { 66 | _getUniquePrefixes(root, ""); 67 | return prefixes; 68 | } 69 | }; 70 | 71 | int main(int argc, char const *argv[]) { 72 | int n; 73 | cin >> n; 74 | Trie t; 75 | while (n--) { 76 | string word; 77 | cin >> word; 78 | t.insert(word); 79 | } 80 | vector prefixes = t.getUniquePrefixes(); 81 | for (auto it : prefixes) cout << it << endl; 82 | return 0; 83 | } 84 | 85 | /* 86 | Input: 87 | 6 88 | and bool bonfire catch case char 89 | 90 | Output: 91 | a 92 | bon 93 | boo 94 | cas 95 | cat 96 | ch 97 | */ -------------------------------------------------------------------------------- /Trie/trie.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Node { 5 | public: 6 | // value: contains the character, children: contains addresses of next characters, isLeaf: true when the string ends 7 | char value; 8 | map children; 9 | bool isLeaf; 10 | Node(char value) { 11 | this->value = value; 12 | this->isLeaf = false; 13 | } 14 | ~Node() { 15 | this->children.clear(); 16 | this->isLeaf = false; 17 | } 18 | }; 19 | 20 | // The trie is case sensative i.e. Hello != hello 21 | class Trie { 22 | private: 23 | Node *root; 24 | int wordCount = 0; 25 | 26 | void _add(Node *parent, string value) { 27 | if (!parent) return; 28 | 29 | // Mark the node as terminating node and increase word count 30 | if (value == "") { 31 | parent->isLeaf = true; 32 | this->wordCount += 1; 33 | return; 34 | } 35 | 36 | // curr: first character of the current string, rest: remaining string 37 | char curr = value[0]; 38 | string rest = value.substr(1); 39 | 40 | // If the parent doesn't already have the curr character as children, create it 41 | if (parent->children.find(curr) == parent->children.end()) { 42 | parent->children[curr] = new Node(curr); 43 | } 44 | 45 | // Then move to the child node and continue until no character is left in the string 46 | _add(parent->children[curr], rest); 47 | } 48 | 49 | bool _isPresent(Node *parent, string value) { 50 | if (!parent) return false; 51 | 52 | // If no character is left in the string and the node is also terminating, the the target string is present 53 | if (value == "") { 54 | if (parent->isLeaf) return true; 55 | return false; 56 | } 57 | 58 | // curr: first character of the current string, rest: remaining string 59 | char curr = value[0]; 60 | string rest = value.substr(1); 61 | 62 | // If the current character is not present in the parent node's children, then the target string is ofc not present 63 | if (parent->children.find(curr) == parent->children.end()) return false; 64 | 65 | // Then move to the child node and continue to check until no character is left 66 | return _isPresent(parent->children[curr], rest); 67 | } 68 | 69 | void _remove(Node *parent, string value) { 70 | if (!parent) return; 71 | 72 | // If all characters of the target string are traversed, then mark the parent node's isLeaf as false as the string is being removed 73 | if (value == "") { 74 | if (parent->isLeaf) parent->isLeaf = false; 75 | this->wordCount -= 1; 76 | return; 77 | } 78 | 79 | // curr: first character of the current string, rest: remaining string 80 | char curr = value[0]; 81 | string rest = value.substr(1); 82 | 83 | // If the current character is not present, then the target string is also not present in the trie so can't remove it as well 84 | if (parent->children.find(curr) == parent->children.end()) return; 85 | 86 | // Then move to the child node and continue until no character is left 87 | _remove(parent->children[curr], rest); 88 | 89 | // Clearing the memory as well: If the parent node's isLeaf is false and it has no children then we remove it as it violates trie's rules i.e. 90 | // it should have atleast one child if it is not isLeaf 91 | if (parent->isLeaf == false && parent->children[curr]->children.empty()) { 92 | parent->children.erase(curr); 93 | } 94 | } 95 | 96 | public: 97 | Trie() { 98 | this->root = new Node('\0'); 99 | this->wordCount = 0; 100 | } 101 | ~Trie() { 102 | delete this->root; 103 | this->wordCount = 0; 104 | } 105 | void add(string value) { this->_add(this->root, value); } 106 | void remove(string value) { this->_remove(this->root, value); } 107 | bool isPresent(string value) { return this->_isPresent(this->root, value); } 108 | int count() { return this->wordCount; } 109 | }; 110 | 111 | int main() { 112 | string stringsPresent[] = {"Hello", "Apple", "Appy", "Arara", "Hi", "Hey"}; 113 | string stringsNotPresent[] = {"Hii", "Aple", "App", "He", "Appl", "Yo", "Mobile"}; 114 | Trie t; 115 | for (string s : stringsPresent) { 116 | t.add(s); 117 | } 118 | for (string s : stringsPresent) { 119 | cout << "Should be present" << endl; 120 | cout << s << ": " << t.isPresent(s) << endl; 121 | } 122 | for (string s : stringsNotPresent) { 123 | cout << "Should not be present" << endl; 124 | cout << s << ": " << t.isPresent(s) << endl; 125 | } 126 | cout << endl; 127 | t.remove("Hello"); 128 | t.remove("Apple"); 129 | t.remove("Hii"); 130 | cout << "Hello: " << t.isPresent("Hello") << endl; 131 | cout << "Apple: " << t.isPresent("Apple") << endl; 132 | cout << "Hii: " << t.isPresent("Hii") << endl; 133 | cout << "Count: Expected: " << 4 << ", Obtained: " << t.count() << endl; 134 | return 0; 135 | } -------------------------------------------------------------------------------- /template.cpp: -------------------------------------------------------------------------------- 1 | // Author: Bihan Chakraborty 2 | // Linkedin: https://www.linkedin.com/in/bihan-chakraborty 3 | // Github: https://github.com/Bihan001 4 | 5 | #include 6 | using namespace std; 7 | 8 | #define ll long long 9 | #define vi vector 10 | #define vll vector 11 | #define pii pair 12 | #define pll pair 13 | #define pb push_back 14 | #define mp make_pair 15 | const int MOD = 1e9 + 7; 16 | const ll INF = 1e18; 17 | #define inputarr(arr, n) \ 18 | for (ll i = 0; i < n; i++) cin >> arr[i]; 19 | #define printarr(arr, n) \ 20 | for (ll i = 0; i < n; i++) cout << arr[i] << ' '; 21 | 22 | void solve() { 23 | int n; 24 | cin >> n; 25 | } 26 | 27 | int main() { 28 | ios_base::sync_with_stdio(false); 29 | cin.tie(0); 30 | cout.tie(0); 31 | int t = 1; 32 | cin >> t; 33 | while (t--) { 34 | solve(); 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /template_small.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define vi vector 5 | #define pb push_back 6 | #define pii pair 7 | #define mii map 8 | const int INF = 0x3f3f3f3f; 9 | const int mod = 1e9 + 7; 10 | 11 | int main(int argc, char const *argv[]) { 12 | int n; 13 | cin >> n; 14 | return 0; 15 | } 16 | --------------------------------------------------------------------------------