├── 02.introToGraph.md ├── 03. GraphRepresentationcpp.md ├── 05.ConnectedComponentsIngraph.md ├── 06.BFS_traversal.md ├── 07.DFS_traversal.md ├── 08.Detect_cycle_BFS.md ├── 09.Detect_cycle_DFS.md ├── 10.checkBipartiteBFS.md ├── 11.CheckBipartiteDFS.md ├── 12_cycle_detection_in_directed_graph_DFS.md ├── 13.topologicalSortDFS.md ├── 14_topo_sort_BFS_kanhs.md ├── 15_cycle_detection_in_directed_graph_BFS_kahn's.md ├── 16.Shortest-Path-in-Undirected-Graph-with-Unit-Weights.md ├── 17.Shortest_path in_DAG.md ├── 18.Dijkstra'sAlgorithm.md ├── 19.MinimumSpanningTree.md ├── 20.PrimsAlgorithmMST.md ├── 23.DisjointSet.md ├── 24. Kruskal's Algorithm.md ├── 25. Bridges In Graph.md ├── 26. Articulation Point.md ├── 27.Kosaraju's Algorithm.md ├── 28. Bellman Ford.md └── README.md /02.introToGraph.md: -------------------------------------------------------------------------------- 1 | ```diff 2 | - text in red 3 | + text in green 4 | ! text in orange 5 | # text in gray 6 | @@ text in purple (and bold)@@ 7 | ``` 8 | # Introduction 9 | 10 | ## Types of graph 11 | 12 | * **Two types of graph:** 13 | * Undirected graph 14 | * Directed graph 15 | 16 | ![Screenshot from 2021-08-27 13-39-30](https://user-images.githubusercontent.com/42698268/131095547-9c02ef4e-83c1-4844-9feb-a136a11db64e.png) 17 | 18 | ## Degree, Indegree and Outdegree 19 | * **Degree, Indegree and Outdegree** 20 | * In Undirected graph 21 | * No of nodes connected with the vertex is called degree in case of undirected graph. 22 | 23 | * In Directed graph 24 | * No of incoming nodes in undirected graph is called indegree. 25 | * No of Outgoing nodes in undirected graph is called outdegree. 26 | 27 | ```diff 28 | 29 | +Total degree of all the nodes in an undirected graph will be equal to the 2 multiplied by total no. of edges, i.e(2xE) 30 | 31 | ``` 32 | as we know that every edge is contibuting for 2 degrees. 33 | 34 | ![Screenshot from 2021-08-27 13-42-52](https://user-images.githubusercontent.com/42698268/131096648-08bd4a3e-192b-41f7-99b5-81a52179ba46.png) 35 | 36 | ## Path 37 | * **Path in a graph** 38 | * **In an undirected graph**: Path is the sequence of nodes or vertex such that none of the nodes are repeating or visited twice in the path 39 | * **In directed graph**: If there is an edge between 1 to 5 then you can go from 1 to 5 but you can't go from 5 to 1. 40 | 41 | ## Cyclic and Acylic 42 | 43 | * **Undirected cyclic graph**: If there is a cycle in an undirected graph then it is called undirected cyclic graph. 44 | 45 | ![Screenshot from 2021-08-27 14-28-55](https://user-images.githubusercontent.com/42698268/131102059-68e234c5-d885-4ac5-af46-110c0f6d7197.png) 46 | 47 | * **Undirected Acylic graph**: If there is no cycle in an undirected graph then it is called undirected acylic graph. 48 | 49 | ![Screenshot from 2021-08-27 14-30-41](https://user-images.githubusercontent.com/42698268/131102077-804a676c-3af2-435c-abe8-998d53421eac.png) 50 | 51 | * **Directed cyclic graph**: If there is a cycle in a directed graph then that is called directed cyclic graph. 52 | 53 | ![Screenshot from 2021-08-27 14-31-12](https://user-images.githubusercontent.com/42698268/131102157-93c0703c-3d9c-4278-8caf-30179f0a6d84.png) 54 | 55 | * **Directed Acylic graph**: If there is no cycle in a directed graph then it is called directed acylic graph, this is commonly known as DAG(will be used many times). 56 | 57 | ![Screenshot from 2021-08-27 14-30-52](https://user-images.githubusercontent.com/42698268/131102178-f5109cb2-7218-4a89-9537-8196e8a5574b.png) 58 | 59 | ### Now the last kind of graph is the weighted graph, all of the above types will be there in the weighted graph also 60 | 61 | # Weighted graph 62 | 63 | * Undirected weighted graph 64 | * Undirected weighted cyclic graph 65 | * Undirected weighted acylic graph 66 | * Directed weighted graph 67 | * Directed weighted cyclic graph 68 | * Directed weighted acylic graph 69 | 70 | ### Important point: If the weights are not given i.e if the graph is unweighted and you are solving a problem where weight is necessary and you need the weight to perform certain operations, consider the weight of each edge to be the unit weight i.e 1. 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /03. GraphRepresentationcpp.md: -------------------------------------------------------------------------------- 1 | # Graph representation 2 | 3 | ## Matrix Representation 4 | 5 | ![Screenshot from 2021-08-27 17-07-55](https://user-images.githubusercontent.com/42698268/131122243-0f14ba40-91c6-4784-b346-c5be36656c75.png) 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | int main(){ 12 | int n, m; 13 | cin>>n>>m; 14 | 15 | //declare the adjacency matrix for graph 16 | //as graph has one based indexing so you have to take the matrix of size 1 greater 17 | //if 0 based indexing, matrix size = mat[m][n] 18 | //if 1 based indexing, matrix size = mat[m+1][n+1] 19 | int mat[n+1][m+1]; 20 | 21 | for(int i=0; i>u>>v; 24 | mat[u][v] = 1; 25 | mat[v][u] = 1; 26 | } 27 | 28 | return 0; 29 | } 30 | ``` 31 | Space complexity : ```O(n^2)``` 32 | So, if the range of n is larger, then we can't create matrix, e.g, if n is 10^5 then we'd need the space of 10^10 to store the matrix, in that case we'd use, **Adjacency List** 33 | 34 | ## Adjacency List representation 35 | It would be a list of vectors, i.e there would be vector for each node and that will store the adjacent nodes list, i.e basically there would be n size array and at each element there would be vector which would store all the adjacent nodes, there would be 2XE adjacent elements in total (in case of undirected graph) where E is total no. of edges, because if there is an edge between 1 and 2 then there is an edge between 2 and 1 also. 36 | ![Screenshot from 2021-08-27 21-00-52](https://user-images.githubusercontent.com/42698268/131158659-f6940472-c699-40cb-9a05-abd5dc0c903b.png) 37 | 38 | 39 | 40 | vector adj[n] 41 | when we'll want to push an element into the adjacency list, we'd say adj[u].push_back(v) and adj[v].push_back(u), this is for undirected graph, but for directed graph only write adj[u].push_back(v) 42 | 43 | 44 | 45 | In case if the graph is weighted then you have to declare it as vector> adj[n], so that you can store the weight, first will store the adjacent node and second will store the weight, and how you'll push it: adj[u].push_back({v, w}) where w represents weight, we'll see while solving questions. 46 | 47 | ![Screenshot from 2021-08-27 21-44-06](https://user-images.githubusercontent.com/42698268/131158726-9ed69c30-d612-4224-99c0-731fdbcf6a00.png) 48 | 49 | **Unweighted graph(0 based Indexing)** 50 | 51 | ```cpp 52 | #include 53 | using namespace std; 54 | 55 | int main(){ 56 | // n = no. of vertices 57 | //m = no. of edges 58 | int n, m; 59 | cin>>n>>m; 60 | 61 | //size will be n as graph is 0 based indexing in our case. 62 | vector adj[n]; 63 | 64 | 65 | for(int i=0; i>u>>v; 68 | 69 | adj[u].push_back(v); 70 | //if the graph is undirected then ommit the next line 71 | adj[v].push_back(u); 72 | } 73 | 74 | return 0; 75 | } 76 | ``` 77 | 78 | 79 | **Unweighted graph(1 based Indexing)** 80 | 81 | ```cpp 82 | #include 83 | using namespace std; 84 | 85 | int main(){ 86 | // n = no. of vertices 87 | //m = no. of edges 88 | int n, m; 89 | cin>>n>>m; 90 | 91 | //size will be n+1 as graph is 1 based indexing in our case. 92 | vector adj[n+1]; 93 | 94 | 95 | for(int i=0; i>u>>v; 98 | 99 | adj[u].push_back(v); 100 | //if the graph is undirected then ommit the next line 101 | adj[v].push_back(u); 102 | } 103 | 104 | return 0; 105 | } 106 | ``` 107 | 108 | Space complexity : ```O(N + 2E)``` 109 | 110 | Weighted Graph 111 | 112 | ```cpp 113 | #include 114 | using namespace std; 115 | 116 | int main(){ 117 | // n = no. of vertices 118 | //m = no. of edges 119 | int n, m; 120 | cin>>n>>m; 121 | 122 | //size will be n+1 as graph is 1 based indexing in our case. 123 | //as graph is weighted so take pair 124 | vector> adj[n+1]; 125 | 126 | for(int i=0; i>u>>v>>wt; 129 | 130 | adj[u].push_back({v, wt}); 131 | adj[v].push_back({u, wt}); 132 | } 133 | 134 | return 0; 135 | } 136 | ``` 137 | Space complexity : ```O(N + 2E) + 2E``` extra 2E because we are creating pair to store weights 138 | -------------------------------------------------------------------------------- /05.ConnectedComponentsIngraph.md: -------------------------------------------------------------------------------- 1 | 2 | # Connected Components in the Graph 3 | 4 | 5 | *If this figure of graph is given in a single question, then you can't say that there are 3 graphs, rather you'll say that this is a disconnected single graph having 3 components.* 6 | 7 | ![Screenshot from 2021-08-27 22-11-15](https://user-images.githubusercontent.com/42698268/131161140-32a6edc0-1030-45d2-8247-eca6eff28ccb.png) 8 | 9 | *This is a single graph having 4 different components* 10 | 11 | ![Screenshot from 2021-08-27 22-13-42](https://user-images.githubusercontent.com/42698268/131161165-2d38cfb5-aee7-4ea7-b26e-1226333b1a30.png) 12 | 13 | *Even a single node can be called as component* 14 | 15 | Next we'll know the traversal techniques(DFS and bFS), but before starting that let us see what are the prerequisites, like something which will be used in every code. 16 | 17 | * You'll always have to take a visited array and initialize it with 0 18 | * You have to traverse through all the components of the graph, so you'll write: 19 | ```cpp 20 | for(i=1; i<=n; i++){ 21 | if(!vis[i]){ 22 | //write your code here 23 | //bfs or dfs whatever you want 24 | } 25 | } 26 | ``` 27 | // this for loop and visited array will make sure that all the disconnected components should be visited. 28 | 29 | You have to always take care of this, you cannot just write the function, you have to write your function for all the components so always take care of this, unless or until the question mentions that the graph has a single component. 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /06.BFS_traversal.md: -------------------------------------------------------------------------------- 1 | # BFS - Breadth First Search 2 | 3 | BFS is a traversal technique, which is recquired to solve any kind of problem, like in array there is a traversal technique, similarly in graph BFS and DFS are the traversal techniques. 4 | 5 | * BFS is a traversal technique in which first we traverse all the adjacent nodes. 6 | 7 | * Let us consider a graph here 8 | 9 | ![Screenshot from 2021-08-28 10-58-48](https://user-images.githubusercontent.com/42698268/131207420-d3a2dc61-ea41-4102-8e42-a4c1e0048a1f.png) 10 | 11 | * Now we can see that there are two components of the graph, now we'll traverse all the adjacent nodes in the first graph then the second graph like this: 12 | 13 | ![Screenshot from 2021-08-28 11-02-25](https://user-images.githubusercontent.com/42698268/131207493-d7104c03-36af-4284-98ba-c50683cba8c3.png) 14 | 15 | ## Steps: 16 | * At first you have to take a visited array of size equal to total no of nodes if graph is 0 based indexing, and size+1 if there is 1 based indexing and mark all of the element as unvisited i.e 0 initially, here we have taken 1 based indexing, so vis[size+1] assigned with 0. 17 | * Now run a for loop for all the nodes, so that none of the components get missed. 18 | 19 | so the general driver code would be 20 | ```cpp 21 | //loop to cover all components 22 | for(int i=1 to n){ 23 | //if the node is not visited 24 | if(!vis[i]) 25 | //call bfs starting from that node 26 | bfs(i); 27 | } 28 | ```` 29 | * Now how would you implement BFS, first we have to take a queue(works in FIFO order) 30 | * Now push the first node taken in the queue and mark it visited (this is the initial step) 31 | 32 | ![Screenshot from 2021-08-28 11-19-29](https://user-images.githubusercontent.com/42698268/131207854-19df905c-0c11-4e02-a6f7-c5a9d003ac25.png) 33 | 34 | * Now we will iterate through the queue until it will not become empty. 35 | * Take out the topmost element out of the queue and delete it from the queue 36 | 37 | ![Screenshot from 2021-08-28 11-19-39](https://user-images.githubusercontent.com/42698268/131207866-ff7c5037-9b2f-4275-851f-ce97cd4bfa35.png) 38 | 39 | * Now whenever you take the element out, it will be stored in the answer i.e BFS 40 | * Now we'll push all the adjacent node of that node into the queue 41 | 42 | ![Screenshot from 2021-08-28 11-19-53](https://user-images.githubusercontent.com/42698268/131207873-040b9dc4-19ca-4332-95e9-ff26c4369457.png) 43 | 44 | ![Screenshot from 2021-08-28 11-20-04](https://user-images.githubusercontent.com/42698268/131207883-7b30014f-39da-4203-be5e-7cccd0d043b4.png) 45 | 46 | 47 | * Remmeber that whenever you'll add anything in the queue, mark it as visited. 48 | * Now repeat the same process until queue will become empty, i.e 49 | * push all the adjacent nodes in the queue 50 | * Mark them as visited while pushing 51 | * Take the top element from the queue and delete it from the queue 52 | * Insert it in answer BFS as right now you are traversing it 53 | * Traverse for all of its unvisited nodes and insert them in queue 54 | * And if your graph has more than 1 components then again this process will happen with the help of for loop. 55 | 56 | ## Time complexity and space complexity 57 | 58 | ### Time complexity 59 | T.C would be ```O(N+E)``` where N is the time taken for visiting N nodes and E is for travelling through adjacent nodes overall. 60 | 61 | ### Space Complexity 62 | S.C would be ```O(N+E) + O(N) + O(N)``` where, O(N+E) for adjacency list, again O(N) for visited array and alst O(N) for storing the answer, i.e, the BFS array. 63 | 64 | ## 0 based Indexing 65 | ```cpp 66 | #include 67 | using namespace std; 68 | 69 | void bfsHelper(int src, vector &vis, vector &bfs, vector adj[]){ 70 | 71 | queue q; 72 | //push the first node in a queue 73 | q.push(src); 74 | //mark it as visited 75 | vis[src] = 1; 76 | //continue until queue will not become empty 77 | while(!q.empty()){ 78 | //take the first node from queue 79 | int node = q.front(); 80 | //delete it from queue 81 | q.pop(); 82 | //push it in answer 83 | bfs.push_back(node); 84 | //traverse for all its adjacent nodes 85 | for(auto it : adj[node]){ 86 | //if it is not visited then push it in a queue and mark it as visited 87 | if(!vis[it]){ 88 | q.push(it); 89 | vis[it] = 1; 90 | } 91 | } 92 | } 93 | } 94 | 95 | vector findBFS(int v, vector adj[]){ 96 | //create visited array to keep track of nodes whether they are visited or not so that they can't be traversed twice 97 | vector vis(v, 0); 98 | //bfs will contain the resultant bfs array 99 | vector bfs; 100 | //do the operation for all the components 101 | for(int i=0; i>n>>m; 114 | //graph has 0 based indexing 115 | //create adjacency list 116 | vector adj[n]; 117 | 118 | //take edges as input 119 | for(int i=0; i>u>>v; 122 | 123 | //this is undirected graph 124 | adj[u].push_back(v); 125 | adj[v].push_back(u); 126 | } 127 | //store and print answer 128 | vector ans = findBFS(n, adj); 129 | for(int i=0; i 140 | using namespace std; 141 | 142 | void bfsHelper(int source, vector &vis, vector &bfsArr, vector adj[]){ 143 | queue q; 144 | q.push(source); 145 | vis[source] = 1; 146 | 147 | while(!q.empty()){ 148 | int node = q.front(); 149 | bfsArr.push_back(node); 150 | q.pop(); 151 | for(auto it : adj[node]){ 152 | if(!vis[it]){ 153 | q.push(it); 154 | vis[it] = 1; 155 | } 156 | } 157 | } 158 | } 159 | 160 | void bfs(int v, vector adj[]){ 161 | vector vis(v+1, 0); 162 | vector bfsArr; 163 | 164 | for(int i=1; i>n>>m; 177 | vector adj[n+1]; 178 | for(int i=0; i>u>>v; 181 | 182 | adj[u].push_back(v); 183 | adj[v].push_back(u); 184 | } 185 | 186 | bfs(n, adj); 187 | return 0; 188 | } 189 | ``` 190 | -------------------------------------------------------------------------------- /07.DFS_traversal.md: -------------------------------------------------------------------------------- 1 | # DfS - Depth First Search 2 | 3 | DFS is a traversing technique in which we traverse the depth first. 4 | 5 | For e.g in this graph, let us say if we'll start from 1 then we'll go to 2 then if it would have been BFS then we'd have gone to 7, but we'll go to depth i.e 4, then 6 and then 7, similarly for the second component we'll go to 3 then 5, you can choose either of the 4 or 7 after 2, will depend on the adjustement of node and how you are traversing. 6 | 7 | ![Screenshot from 2021-08-28 18-44-37](https://user-images.githubusercontent.com/42698268/131219223-a18b2e52-1efa-43a5-ae36-4b73981c146f.png) 8 | 9 | The driver code would be same as BFS 10 | 11 | ![Screenshot from 2021-08-28 18-49-07](https://user-images.githubusercontent.com/42698268/131219299-274cdf8f-5ce5-4735-9b87-d4d38f334e23.png) 12 | 13 | Now the process of DFS is done recursively that is why first it goes for the depth of the first node, then goes for it's next adjacent(if not visited), i.e left portion will be executed first then the right portion will be called after finishing the execution of left one. 14 | ![Screenshot from 2021-08-28 19-56-39](https://user-images.githubusercontent.com/42698268/131221246-c2d11204-8f22-4235-b860-b93679df085c.png) 15 | 16 | ## Time complexity and space complexity 17 | * Time complexity would be ```O(N+E)```, N is the time taken for visiting N nodes and E is for traveling through adjacent nodes overall 18 | * Space complexity would be ```O(N+E) + O(N) + O(N)``` same as BFS 19 | N+E for adjacency list, N for visited array and other N for auxiliary space. 20 | 21 | ## 0 Based Indexing 22 | ```cpp 23 | #include 24 | using namespace std; 25 | 26 | void dfs(int node, vector &vis, vector &storeDFS, vector adj[]){ 27 | storeDFS.push_back(node); 28 | vis[node] = 1; 29 | for(auto it : adj[node]){ 30 | if(!vis[it]){ 31 | dfs(it, vis, storeDFS, adj); 32 | } 33 | } 34 | } 35 | 36 | vector findDFS(int v, vector adj[]){ 37 | vector vis(v, 0); 38 | vector storeDFS; 39 | 40 | for(int i=0; i>n>>m; 51 | 52 | vector adj[n]; 53 | for(int i=0; i>u>>v; 56 | 57 | adj[u].push_back(v); 58 | adj[v].push_back(u); 59 | } 60 | vector ans = findDFS(n, adj); 61 | for(int i=0; i 72 | using namespace std; 73 | 74 | void dfsHelper(int node, vector &vis, vector &dfsArr, vector adj[]){ 75 | dfsArr.push_back(node); 76 | vis[node] = 1; 77 | 78 | for(auto it : adj[node]){ 79 | if(!vis[it]){ 80 | dfsHelper(it, vis, dfsArr, adj); 81 | } 82 | } 83 | } 84 | 85 | void dfs(int v, vector adj[]){ 86 | vector vis(v+1, 0); 87 | vector dfsArr; 88 | 89 | for(int i=1; i>n>>m; 102 | vector adj[n+1]; 103 | for(int i=0; i>u>>v; 106 | 107 | adj[u].push_back(v); 108 | adj[v].push_back(u); 109 | } 110 | 111 | dfs(n, adj); 112 | return 0; 113 | } 114 | ``` 115 | -------------------------------------------------------------------------------- /08.Detect_cycle_BFS.md: -------------------------------------------------------------------------------- 1 | # Detect Cycle - BFS 2 | 3 | Thought Process: ``` If any of the adjacent node other than parent is already visited then there is a cycle ``` 4 | 5 | Driver code would be same, the difference is just that we'd implement this using BFS 6 | 7 | ![Screenshot from 2021-08-29 13-07-42](https://user-images.githubusercontent.com/42698268/131242624-8aec3194-591e-47fc-a2d9-d4b966e352d1.png) 8 | 9 | Till now, everything would be same as how we detected using DFS 10 | 11 | Now let us find out, how we'd implement this using BFS, we know that we use queue to implement BfS, here it would be implemented slight differenctly, we'd take node as well as parent in the queue, ie ```queue>``` and initially parent will be -1. 12 | 13 | ![Screenshot from 2021-08-29 16-29-20](https://user-images.githubusercontent.com/42698268/131248051-2c25ee60-ad2f-4d31-8ee0-b77cb34bf6a1.png) 14 | 15 | ## Time Complexity and Space complexity: 16 | * Time complexity would be same as DFS i,e ``` O(N+E) ``` N is time taken for visiting N nodes, and E is for traveling through adjacent nodes overall. 17 | * Space Complexity would be ```O(N+E) + O(N) + O(N) ``` for adjacency list, visited array and queue. 18 | 19 | ## 0 Based Indexing 20 | 21 | ```cpp 22 | #include 23 | using namespace std; 24 | 25 | bool checkCycleBFS(int src, vector &vis, vector adj[]){ 26 | queue> q; 27 | vis[src] = 1; 28 | q.push({src, -1}); 29 | 30 | while(!q.empty()){ 31 | int node = q.front().first; 32 | int par = q.front().second; 33 | q.pop(); 34 | 35 | for(auto it : adj[node]){ 36 | if(!vis[it]){ 37 | vis[it] = 1; 38 | q.push({it, node}); 39 | } 40 | else if(it != par) return true; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | bool isCycle(int v, vector adj[]){ 47 | vector vis(v, 0); 48 | 49 | 50 | for(int i=0; i>n>>m; 61 | 62 | vector adj[n]; 63 | for(int i=0; i>u>>v; 66 | 67 | adj[u].push_back(v); 68 | adj[v].push_back(u); 69 | } 70 | if(isCycle(n, adj)) cout<<"Yes"; 71 | else cout<<"No"; 72 | return 0; 73 | } 74 | ``` 75 | 76 | ## 1 Based Indexing 77 | ```cpp 78 | #include 79 | using namespace std; 80 | 81 | bool checkCycleBFS(int src, vector &vis, vector adj[]){ 82 | queue> q; 83 | vis[src] = 1; 84 | q.push({src, -1}); 85 | 86 | while(!q.empty()){ 87 | int node = q.front().first; 88 | int par = q.front().second; 89 | q.pop(); 90 | 91 | for(auto it : adj[node]){ 92 | if(!vis[it]){ 93 | vis[it] = 1; 94 | q.push({it, node}); 95 | } 96 | else if(it != par) return true; 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | bool isCycle(int v, vector adj[]){ 103 | vector vis(v+1, 0); 104 | 105 | 106 | for(int i=1; i<=v; i++){ 107 | if(!vis[i]){ 108 | if(checkCycleBFS(i, vis, adj)) return true; 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | int main(){ 115 | int n, m; 116 | cin>>n>>m; 117 | 118 | vector adj[n+1]; 119 | for(int i=0; i>u>>v; 122 | 123 | adj[u].push_back(v); 124 | adj[v].push_back(u); 125 | } 126 | if(isCycle(n, adj)) cout<<"Yes"; 127 | else cout<<"No"; 128 | return 0; 129 | } 130 | ``` 131 | -------------------------------------------------------------------------------- /09.Detect_cycle_DFS.md: -------------------------------------------------------------------------------- 1 | # Detect Cycle - DFS 2 | 3 | Thought Process: ``` If any of the adjacent node other than parent is already visited then there is a cycle ``` 4 | 5 | Driver code would be same, We'll call dfs for all the components, it is just that the dfs would be implemmented in a little different way. 6 | 7 | ![Screenshot from 2021-08-28 22-01-17](https://user-images.githubusercontent.com/42698268/131224654-c41e11fb-ecac-4a3d-9540-63349d77cf15.png) 8 | 9 | 10 | Here in this graph, we'll call DFS for each node one by one, in the order 2->3->6->7->8 but now when DFS will be called for 8, then it will call it's adjacent node, i.e, 5. Then we'll find out that 5 is already visited, so it can only be visited if we are trying to access it the second time, that does mean there is a cycle. Had it not been a cycle then we would have never got a node which is already visited. 11 | 12 | * But there is a twist here, whenever you'll traverse you'll always have one adjacent node which would be always visited i.e, the previous node, so we have to see that apart from the previous node if there is any node which is already visited then only we'll claim that there is a cycle, so we'll always carry parent. 13 | 14 | * while calling it for the first time, pass the parent as -1, as parent of 1st node is none. 15 | * Now steps would be: 16 | * Call dfs for first node and pass parent as -1 17 | * Mark it as visited 18 | * Check if any of the adjacent node is visited apart from the parent then there is a cycle so return true. 19 | * If not visited then call dfs for its adjacent nodes. 20 | * so until last if no one return true then return false, i.e, there isn't any cycle. 21 | * The moment anyone return true, brak from there as we don't need to find out the number of cycles, we jsut need to find out whether there is a cycle or not, so no need to traverse further. 22 | * Similarly for the components, if any of the component returns true, then break from there, no need to check for other components. 23 | 24 | ![Screenshot from 2021-08-28 22-32-17](https://user-images.githubusercontent.com/42698268/131242411-e98010a8-e7eb-4418-86cc-bb691de6077a.png) 25 | 26 | 27 | ## Time Complexity and Space complexity: 28 | * Time complexity would be same as DFS i,e ``` O(N+E) ``` N is time taken for visiting N nodes, and E is for traveling through adjacent nodes overall. 29 | * Space Complexity would be ```O(N+E) + O(N) + O(N) ``` for adjacency list, visited array and auxilliary space. 30 | 31 | ## 0 Based Indexing 32 | ```cpp 33 | #include 34 | using namespace std; 35 | 36 | bool checkCycleDFS(int node, int par, vector &vis, vector adj[]){ 37 | vis[node] = 1; 38 | for(auto it : adj[node]){ 39 | if(!vis[it]){ 40 | if(checkCycleDFS(it, node, vis, adj)) return true; 41 | } 42 | else if(it != par) return true; 43 | } 44 | return false; 45 | } 46 | 47 | bool isCycle(int v, vector adj[]){ 48 | vector vis(v, 0); 49 | 50 | 51 | for(int i=0; i>n>>m; 62 | 63 | vector adj[n]; 64 | for(int i=0; i>u>>v; 67 | 68 | adj[u].push_back(v); 69 | adj[v].push_back(u); 70 | } 71 | if(isCycle(n, adj)) cout<<"Yes"; 72 | else cout<<"No"; 73 | return 0; 74 | } 75 | ``` 76 | 77 | ## 1 Based Indexing 78 | ```cpp 79 | #include 80 | using namespace std; 81 | 82 | bool checkCycleDFS(int node, int par, vector &vis, vector adj[]){ 83 | vis[node] = 1; 84 | for(auto it : adj[node]){ 85 | if(!vis[it]){ 86 | if(checkCycleDFS(it, node, vis, adj)) return true; 87 | } 88 | else if(it != par) return true; 89 | } 90 | return false; 91 | } 92 | 93 | bool isCycle(int v, vector adj[]){ 94 | vector vis(v+1, 0); 95 | 96 | 97 | for(int i=1; i<=v; i++){ 98 | if(!vis[i]){ 99 | if(checkCycleDFS(i, -1, vis, adj)) return true; 100 | } 101 | } 102 | return false; 103 | } 104 | 105 | int main(){ 106 | int n, m; 107 | cin>>n>>m; 108 | 109 | vector adj[n+1]; 110 | for(int i=0; i>u>>v; 113 | 114 | adj[u].push_back(v); 115 | adj[v].push_back(u); 116 | } 117 | if(isCycle(n, adj)) cout<<"Yes"; 118 | else cout<<"No"; 119 | return 0; 120 | } 121 | ``` 122 | -------------------------------------------------------------------------------- /10.checkBipartiteBFS.md: -------------------------------------------------------------------------------- 1 | # Check if Graph is Bipartite using BFS 2 | 3 | ![Screenshot from 2021-08-29 17-10-29](https://user-images.githubusercontent.com/42698268/131254721-946624cb-748d-4558-8970-4f8b949ac728.png) 4 | 5 | Thought Process: ```If the graph doesn't have odd length cycle then it is bipartite graph``` or you can say that ```if the graph have odd length cycle it will never be bipartite``` 6 | 7 | 8 | Steps: 9 | 10 | * Take an array of size equal to total no. of nodes and assign it with -1, i.e all the nodes are non coloured yet 11 | * consider 0 and 1 as two colors, and -1 as non -coloured 12 | * initialize the first node with any color 13 | * Traverse the graph using BFS method 14 | * if any of the component of graph returns false then ans will be No 15 | * If a node is not coloured, color all the adjacent nodes of a node with the opposite color of its parent 16 | * If a node is coloured then check whether the color is same as the color of parent or not 17 | * If the color of adjacent node is same as parent then return false. 18 | ![Screenshot from 2021-08-29 19-36-20](https://user-images.githubusercontent.com/42698268/131254730-f88ac6fc-fab5-4313-bdb7-b38412f9299c.png) 19 | 20 | The above graph is not bipartite because we can't color it using two different colors, the reason is that the cycle is of odd length 21 | 22 | 23 | ## Time complexity and space complexity 24 | * Time complexity would be ```O(N+E)``` 25 | * Space complexity would be ```O(N+E) + O(N) + O(N)``` for adjacency list, queue, color array 26 | 27 | ## 0 Based Indexing 28 | ```cpp 29 | #include 30 | using namespace std; 31 | 32 | bool checkBipartite(int src, int color[], vector adj[]){ 33 | queue q; 34 | color[src] = 1; 35 | q.push(src); 36 | 37 | while(!q.empty()){ 38 | int node = q.front(); 39 | q.pop(); 40 | for(auto it : adj[node]){ 41 | if(color[it]==-1){ 42 | color[it] = 1-color[node]; 43 | q.push(it); 44 | } 45 | else if(color[it] == color[node]) return false; 46 | } 47 | } 48 | return true; 49 | } 50 | 51 | bool bipartite(int v, vector adj[]){ 52 | int color[v]; 53 | memset(color, -1, sizeof color); 54 | 55 | for(int i=0; i>n>>m; 67 | 68 | vector adj[n]; 69 | for(int i=0; i>u>>v; 72 | 73 | adj[u].push_back(v); 74 | adj[v].push_back(u); 75 | 76 | } 77 | 78 | if(bipartite(n, adj)) cout<<"Yes"; 79 | else cout<<"No"; 80 | 81 | return 0; 82 | } 83 | ``` 84 | 85 | ## 1 Based Indexing 86 | 87 | ```cpp 88 | #include 89 | using namespace std; 90 | 91 | bool checkBipartite(int src, int color[], vector adj[]){ 92 | queue q; 93 | color[src] = 1; 94 | q.push(src); 95 | 96 | while(!q.empty()){ 97 | int node = q.front(); 98 | q.pop(); 99 | for(auto it : adj[node]){ 100 | if(color[it]==-1){ 101 | color[it] = 1-color[node]; 102 | q.push(it); 103 | } 104 | else if(color[it] == color[node]) return false; 105 | } 106 | } 107 | return true; 108 | } 109 | 110 | bool bipartite(int v, vector adj[]){ 111 | int color[v+1]; 112 | memset(color, -1, sizeof color); 113 | 114 | for(int i=1; i<=v; i++){ 115 | if(color[i] == -1){ 116 | if(!checkBipartite(i, color, adj)) return false; 117 | } 118 | } 119 | 120 | return true; 121 | } 122 | 123 | int main(){ 124 | int n, m; 125 | cin>>n>>m; 126 | 127 | vector adj[n+1]; 128 | for(int i=0; i>u>>v; 131 | 132 | adj[u].push_back(v); 133 | adj[v].push_back(u); 134 | 135 | } 136 | 137 | if(bipartite(n, adj)) cout<<"Yes"; 138 | else cout<<"No"; 139 | 140 | return 0; 141 | } 142 | 143 | ``` 144 | -------------------------------------------------------------------------------- /11.CheckBipartiteDFS.md: -------------------------------------------------------------------------------- 1 | # Check Bipartite - Using DFS 2 | Process will be same as BFS, just it would work recursively for the DFS and whwnever will get an adjacent node with the same color then will return false 3 | 4 | ![Screenshot from 2021-08-29 20-37-54](https://user-images.githubusercontent.com/42698268/131255393-818c251c-1d46-48ce-806c-886336412e52.png) 5 | 6 | 7 | ## 0 Based Indexing 8 | 9 | ```cpp 10 | #include 11 | using namespace std; 12 | 13 | bool bipartitedfs(int node, int color[], vector adj[]){ 14 | //if not colored then color the node, this will run just for the first node of any component 15 | if(color[node] == -1) color[node] = 1; 16 | 17 | //traverse for all adjacent nodes 18 | for(auto it : adj[node]){ 19 | //if not colored then color it and call recursion 20 | if(color[it] == -1){ 21 | color[it] = 1-color[node]; 22 | //if at any point recursion returns false then return false, no need to check further 23 | if(!bipartitedfs(it, color, adj)) return false; 24 | } 25 | //if node is already colored with the same color as parent then return false 26 | else if(color[it] == color[node]) return false; 27 | } 28 | 29 | //if all condition passes then return true 30 | return true; 31 | } 32 | 33 | bool bipartite(int v, vector adj[]){ 34 | int color[v]; 35 | memset(color, -1, sizeof color); 36 | for(int i=0; i>n>>m; 47 | 48 | vector adj[n]; 49 | for(int i=0; i>u>>v; 52 | 53 | adj[u].push_back(v); 54 | adj[v].push_back(u); 55 | } 56 | 57 | if(bipartite(n, adj)) cout<<"Yes"; 58 | else cout<<"No"; 59 | 60 | return 0; 61 | } 62 | ``` 63 | 64 | ## 1 Based Indexing 65 | 66 | ```cpp 67 | #include 68 | using namespace std; 69 | 70 | bool bipartitedfs(int node, int color[], vector adj[]){ 71 | //if not colored then color the node, this will run just for the first node of any component 72 | if(color[node] == -1) color[node] = 1; 73 | 74 | //traverse for all adjacent nodes 75 | for(auto it : adj[node]){ 76 | //if not colored then color it and call recursion 77 | if(color[it] == -1){ 78 | color[it] = 1-color[node]; 79 | //if at any point recursion returns false then return false, no need to check further 80 | if(!bipartitedfs(it, color, adj)) return false; 81 | } 82 | //if node is already colored with the same color as parent then return false 83 | else if(color[it] == color[node]) return false; 84 | } 85 | 86 | //if all condition passes then return true 87 | return true; 88 | } 89 | 90 | bool bipartite(int v, vector adj[]){ 91 | int color[v+1]; 92 | memset(color, -1, sizeof color); 93 | for(int i=1; i<=v; i++){ 94 | if(color[i] == -1){ 95 | if(!bipartitedfs(i, color, adj)) return false; 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | int main(){ 102 | int n, m; 103 | cin>>n>>m; 104 | 105 | vector adj[n+1]; 106 | for(int i=0; i>u>>v; 109 | 110 | adj[u].push_back(v); 111 | adj[v].push_back(u); 112 | } 113 | 114 | if(bipartite(n, adj)) cout<<"Yes"; 115 | else cout<<"No"; 116 | 117 | return 0; 118 | } 119 | 120 | ``` 121 | -------------------------------------------------------------------------------- /12_cycle_detection_in_directed_graph_DFS.md: -------------------------------------------------------------------------------- 1 | # Detect cycle in directed graph 2 | 3 | Here we can't use the old method which we had used in undirected graph, as in undirected graph we had kept the track of visited array which would tell us that if you visit the node again then it has cycle, but here we can see that in this example 4 | 5 | ![Screenshot from 2021-08-29 20-46-11](https://user-images.githubusercontent.com/42698268/131255981-301d9f49-9317-4559-9ca8-2c5888c01e61.png) 6 | 7 | 8 | ![Screenshot from 2021-08-29 20-46-21](https://user-images.githubusercontent.com/42698268/131255983-8cb279a3-d36e-4b89-ae65-c0b38804a5b6.png) 9 | 10 | If we'll have a visited array then for the nodes 3, 4, 5, 6, it will tell us that it is a cycle because when we'll go to 3 then 4 then 5 and mark all 3 as visited, now when we'll go to 6 it will tell us that there is an adjacent node to 6 whic is already visited and that is 5, but it doesn't know that it is stil not making a cycle so along with visited array, we'll keep track of directed visited i.e, we'll take a dfsVis which will tell us that whetehr the particular node is visited for this direction or not. 11 | 12 | ![Screenshot from 2021-08-29 21-01-06](https://user-images.githubusercontent.com/42698268/131256106-2db59f55-3e9a-41c0-b388-0f6af419196e.png) 13 | 14 | what we will do is, we'll have two visited arrays called ```vis``` and a ```dfsVis```, whenever we will visit a node we will mark it as visited in vis as well as dfsVis, but when the dfs function will return i.e we are returning from that node because there is no further nodes to visit so we'll mark the dfsVis to be 0 again because now we are returning from that direction. 15 | 16 | # Time complexity and space complexity 17 | * Time complexity would be ```O(N+E)``` due to simple DFS call 18 | * Space complexity would be ``` O(N+E) + O(N) + O(N) + O(N)``` adjacency list, visited array, dfs visited and auxilliary space for dfs call 19 | 20 | ## 0 Based Indexing 21 | 22 | ```cpp 23 | #include 24 | using namespace std; 25 | 26 | bool checkCycle(int node, int visited[], int dfsvisited[], vector adj[]){ 27 | visited[node] = 1; 28 | dfsvisited[node] = 1; 29 | 30 | for(auto it : adj[node]){ 31 | if(!visited[it]){ 32 | if(checkCycle(it, visited, dfsvisited, adj)) return true; 33 | } 34 | else if(dfsvisited[it]) return true; 35 | } 36 | dfsvisited[node]=0; 37 | return false; 38 | } 39 | 40 | bool cycle(int v, vector adj[]){ 41 | int visited[v]; 42 | int dfsvisited[v]; 43 | 44 | memset(visited, 0, sizeof visited); 45 | memset(dfsvisited, 0, sizeof dfsvisited); 46 | 47 | for(int i=0; i>n>>m; 58 | 59 | vector adj[n]; 60 | for(int i=0; i>u>>v; 63 | 64 | adj[u].push_back(v); 65 | } 66 | if(cycle(n, adj)) cout<<"Yes"; 67 | else cout<<"No"; 68 | 69 | return 0; 70 | } 71 | ``` 72 | 73 | ## 1 Based Indexing 74 | 75 | ```cpp 76 | #include 77 | using namespace std; 78 | 79 | bool checkCycle(int node, int visited[], int dfsvisited[], vector adj[]){ 80 | visited[node] = 1; 81 | dfsvisited[node] = 1; 82 | 83 | for(auto it : adj[node]){ 84 | if(!visited[it]){ 85 | if(checkCycle(it, visited, dfsvisited, adj)) return true; 86 | } 87 | else if(dfsvisited[it]) return true; 88 | } 89 | dfsvisited[node]=0; 90 | return false; 91 | } 92 | 93 | bool cycle(int v, vector adj[]){ 94 | int visited[v+1]; 95 | int dfsvisited[v+1]; 96 | 97 | memset(visited, 0, sizeof visited); 98 | memset(dfsvisited, 0, sizeof dfsvisited); 99 | 100 | for(int i=1; i<=v; i++){ 101 | if(visited[i] == 0){ 102 | if(checkCycle(i, visited, dfsvisited, adj)) return true; 103 | } 104 | } 105 | return false; 106 | } 107 | 108 | int main(){ 109 | int n, m; 110 | cin>>n>>m; 111 | 112 | vector adj[n+1]; 113 | for(int i=0; i>u>>v; 116 | 117 | adj[u].push_back(v); 118 | } 119 | if(cycle(n, adj)) cout<<"Yes"; 120 | else cout<<"No"; 121 | 122 | return 0; 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /13.topologicalSortDFS.md: -------------------------------------------------------------------------------- 1 | # Topological Sorting 2 | 3 | ![Screenshot from 2021-08-29 21-19-25](https://user-images.githubusercontent.com/42698268/131256760-ccd1abc5-655d-4869-a25a-f0b929981664.png) 4 | 5 | Topological sorting is only possible in DAG i.e directed acyclic graph 6 | * It is not possible in undirected graph, because if there is an edge between 1 and 2, you can't say that 1 should come before 2 or 2 should come before 1 7 | * It is also not possible in directed cyclic graph because 8 | 9 | ![Screenshot from 2021-08-29 21-23-22](https://user-images.githubusercontent.com/42698268/131256849-0febf3b0-f38d-493a-b2ec-bf83457645c9.png) 10 | 11 | because here you can see that this is directed cyclic graph and we cant say that 2 should come before 3 and 2 sould come before 4 also 4 should come before 2, there is a contardiction, that is why topo sort is used only for DAG 12 | 13 | We'd just push the node whose dfs call is over into the stack after marking it as visited, and at last just pop all the elements of the stack and print it. 14 | 15 | # Time complexity and space complexity 16 | * Time complexity would be ```O(N+E)``` as this is using simple DFS 17 | * space complexity would be ```O(N+E) + O(N) + O(N) + O(N)``` for adjacency list, vis array, for stack and for DFS call. 18 | 19 | ## 0 Based Indexing 20 | ```cpp 21 | #include 22 | using namespace std; 23 | 24 | void findTopoSort(int node, vector &vis, stack &st, vector adj[]){ 25 | vis[node] = 1; 26 | for(auto it : adj[node]){ 27 | if(!vis[it]){ 28 | findTopoSort(it, vis, st, adj); 29 | } 30 | } 31 | st.push(node); 32 | } 33 | 34 | vector topSort(int v, vector adj[]){ 35 | stack st; 36 | vector vis(v, 0); 37 | 38 | for(int i=0; i topo; 44 | while(!st.empty()){ 45 | topo.push_back(st.top()); 46 | st.pop(); 47 | } 48 | 49 | return topo; 50 | } 51 | int main(){ 52 | int n, m; 53 | cin>>n>>m; 54 | 55 | vector adj[n]; 56 | for(int i=0; i>u>>v; 59 | 60 | adj[u].push_back(v); 61 | } 62 | 63 | vector ans = topSort(n, adj); 64 | 65 | for(int i=0; i 76 | using namespace std; 77 | 78 | void findTopoSort(int node, vector &vis, stack &st, vector adj[]){ 79 | vis[node] = 1; 80 | for(auto it : adj[node]){ 81 | if(!vis[it]){ 82 | findTopoSort(it, vis, st, adj); 83 | } 84 | } 85 | st.push(node); 86 | } 87 | 88 | vector topSort(int v, vector adj[]){ 89 | stack st; 90 | vector vis(v+1, 0); 91 | 92 | for(int i=1; i<=v; i++){ 93 | if(!vis[i]){ 94 | findTopoSort(i, vis, st, adj); 95 | } 96 | } 97 | vector topo; 98 | while(!st.empty()){ 99 | topo.push_back(st.top()); 100 | st.pop(); 101 | } 102 | 103 | return topo; 104 | } 105 | int main(){ 106 | int n, m; 107 | cin>>n>>m; 108 | 109 | vector adj[n+1]; 110 | for(int i=0; i>u>>v; 113 | 114 | adj[u].push_back(v); 115 | } 116 | 117 | vector ans = topSort(n, adj); 118 | 119 | for(int i=0; i 34 | using namespace std; 35 | 36 | vector topoSortBFS(int v, vector adj[]){ 37 | queue q; 38 | vector inDegree(v, 0); 39 | vector topo; 40 | 41 | //store the in degree of all nodes 42 | for(int i=0; i>n>>m; 75 | 76 | vector adj[n]; 77 | for(int i=0; i>u>>v; 80 | 81 | adj[u].push_back(v); 82 | } 83 | 84 | vector ans = topoSortBFS(n, adj); 85 | for(int i=0; i 7 | using namespace std; 8 | 9 | // the basic idea is to check if the graph can generate topological sort array, then it does not contain cycle 10 | // because we know that graph can generate topo sort only if it is DAG 11 | // so just write the code of topo sort and find out if the length of generated topo sort is equal to number of vertices then it does not contain cycle 12 | 13 | bool cycleBFS(int v, vector adj[]){ 14 | queue q; 15 | vector inDegree(v, 0); 16 | 17 | //find the indegree of all the nodes 18 | for(int i=0; i>n>>m; 53 | 54 | vector adj[n]; 55 | for(int i=0; i>u>>v; 58 | 59 | adj[u].push_back(v); 60 | 61 | } 62 | 63 | if(cycleBFS(n, adj)) cout<<"Yes"; 64 | else cout<<"No"; 65 | 66 | return 0; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /16.Shortest-Path-in-Undirected-Graph-with-Unit-Weights.md: -------------------------------------------------------------------------------- 1 | # Shortest Path in Undirected Graph with Unit Weights 2 | 3 | As we can see that the graph is undirected as well and unweighted, so whenever the graph is undirected as well as unweighted, we assume that all the edges are weighted as 1. 4 | 5 | Now we will be given a source, and we have to find the shortest path from source to all nodes, let us assume that source is 0th vertex for now, we'll find the shortest path using BFS, for that we'll have a queue for traversing all vertices and it's adjacent nodes and we'll have a distance array initialized with infinity, considering the initial distance of all the nodes from source to be infinity. 6 | 7 | * Create a distance array which will store the shortest path from source to all vertices 8 | * Initialize all the elements of the distance array with infinity 9 | * Assign the dist of source element as 0, because distance between source and source is always zero 10 | * create a queue 11 | * Push the source node into queue 12 | * Traverse while queue will become empty 13 | * Take out the node from queue 14 | * traverse all it's adjacent nodes 15 | * if the distance already stored in that node i.e dis[node] + 1 is smaller than the dis 16 | 17 | ```C++ 18 | #include 19 | using namespace std; 20 | 21 | void shortest_path(int v, int src, vector adj[]){ 22 | //create a distance array and initialize it with infinity 23 | int dis[v]; 24 | for(int i=0; i q; 32 | q.push(src); 33 | 34 | //update if path is smaller 35 | while(!q.empty()){ 36 | int node = q.front(); 37 | q.pop(); 38 | 39 | for(auto it : adj[node]){ 40 | if((dis[node] + 1)>n>>m; 52 | 53 | vector adj[n]; 54 | for(int i=0; i>u>>v; 57 | 58 | adj[u].push_back(v); 59 | adj[v].push_back(u); 60 | } 61 | 62 | shortest_path(n, adj); 63 | return 0; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /17.Shortest_path in_DAG.md: -------------------------------------------------------------------------------- 1 | # Find shortest path between source to all the edges in a DAG 2 | 3 | Thought Process: ```use Topo sort to find out the shortest distance between source to each vertex ``` 4 | 5 | ![Screenshot from 2021-08-31 12-12-38](https://user-images.githubusercontent.com/42698268/131455054-1f7e170c-70ee-45e4-bbed-d9517287e6bb.png) 6 | 7 | 8 | As this is a weighted graph so we are going to store the edge weights in adjacency list using pair, i.e ```vector> adj[] ```, it will store the edge and it's weight 9 | 10 | 11 | ![Screenshot from 2021-08-31 12-31-33](https://user-images.githubusercontent.com/42698268/131457721-0eae33f3-96c7-4a2c-b885-6a2fd6947cc2.png) 12 | 13 | ## Steps: 14 | * Find topo sort in a given DAG and store it in a stack 15 | * Create a distance array and initialize it with infinity 16 | * Assign the source of distance array to be zero. 17 | * Run a loop until stack will become empty 18 | * Pop elements one by one from a stack 19 | * If that node is not visited then only Go to all the adjacent nodes of fetched element and update the distance array if ```dist[parent node] + distance of parent node to that < dist[it] ``` 20 | 21 | ## Time and space complexity 22 | * Time complexity would be ```O(N+E) * 2 ``` the first O(N+E) for finding the topo sort as we are using DFS to find the topo sort and 2nd O(N+E) because we are again implementing a BFS kind of algorithm to find the distance 23 | * Space complexity would be ```O(2N) ``` for stack and distance array 24 | * If you'll use DFS then there will be auxilliary space complexity, i fyou'll use BFS then there will be no auxilliary space complexity 25 | 26 | Intuition behind using topo sort here instead of simple bfs or dfs: 27 | 28 | ``` For all who are wondering the intution behind Topological sorting and why haven't we use simple DFS or BFS from the source node instead, lets say you want to do it using DFS. yes you can do it using DFS , but consider the case when you already updated a node's distance by a dfs() call and lets say its 7 and as it is DFS then its obvious that you also have updated all the nodes in its segment of DFS call . now you have reached to the same node from different dfs() call and now the distance is 4 , so in order to update all the nodes which were affected by the DFS call previously on the node considering distance as 7 , you now again have to do the same so that its updated with new min distance.Same is the scenario for the simple BFS approach.This multiple time calling DFS/BFS degrades the Time Complexity, hence Topological Ordering save you from that overhead as you already know which nodes will come after the current node , so you keep on updating it ``` 29 | 30 | --------- 31 | 32 | ``` When you use a bfs, you are not sure which is the starting point, hence it might happen you have to iterate in the queue many times, when you use topo sort, you are sure this is the first node which has no incoming nodes. Hence you start from the starting point, hence taking lesser amount of time.While using BFS, you are not sure if your source is the starting point or not, if it is not, then you will be taking extra turns. ``` 33 | 34 | 35 | 36 | 37 | ## Code 38 | 39 | ```cpp 40 | 41 | #include 42 | using namespace std; 43 | 44 | void topoSort(int src, stack &st, vector &vis, vector> adj[]){ 45 | vis[src] = 1; 46 | for(auto it:adj[src]){ 47 | //to access the node we have to write it.first 48 | //as in the pair, first is node data, second is weight 49 | if(!vis[it.first]){ 50 | //the next node data which would be passed as source would be it.first 51 | topoSort(it.first, st, vis, adj); 52 | } 53 | } 54 | st.push(src); 55 | } 56 | void findShortestPath(int v, int src, vector> adj[]){ 57 | stack st; 58 | vector vis(v, 0); 59 | for(int i=0; i>n>>m; 89 | 90 | vector> adj[n]; 91 | for(int i=0; i>u>>v>>wt; 94 | adj[u].push_back({v, wt}); 95 | } 96 | int src = 0; 97 | findShortestPath(n, src, adj); 98 | return 0; 99 | } 100 | 101 | 102 | 103 | ``` 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /18.Dijkstra'sAlgorithm.md: -------------------------------------------------------------------------------- 1 | # Dijkstra's Algorithm ( to find the minimum distance between source and all the nodes) 2 | 3 | ![Screenshot from 2021-08-31 16-23-33](https://user-images.githubusercontent.com/42698268/131495716-24d0110e-dede-4ad5-8f23-5febbbf8f237.png) 4 | 5 | Adjacency list: 6 | 7 | ![Screenshot from 2021-08-31 16-23-40](https://user-images.githubusercontent.com/42698268/131495779-c02cad6c-510e-447e-915e-45069ff37173.png) 8 | 9 | 10 | Though process: ```We'll use greedy to find the shortest path ``` 11 | 12 | Steps: 13 | * Create a priority queue of min heap so that the one having the shortest distance would be in front 14 | * Create a dist array and initialize it with infinity and assign the dist[src] = 0 15 | * Now push the source into the priority queue 16 | * Run until queue will not become empty 17 | * Pop out the front element and traverse for all adjacent nodes, if any of them is eligible to update then update dist array and push that node along with its distance from source into the priority queue 18 | 19 | 20 | 21 | ![Screenshot from 2021-08-31 15-44-00](https://user-images.githubusercontent.com/42698268/131495652-55b0a517-9ee2-44a2-8dce-50ca17bb007e.png) 22 | 23 | 24 | Imp Note: 25 | 26 | While doing this whole thing, you'll find out that sometime you'll have same distance in your priorrity queue more than once, so why we the same node with different distances is in the priority queue, the answer is that while doing this process whenever we'll find out a node having less dist than the already present in the dist array so we'll update it in our queue, but if at some point we'd find out that the same node is getting updated because we've found a path with less distance then the previous then we'll also update it in our queue, and the good thing is that, always that one would be used for the next process which has the least weight among all the pushed ones because this is priority queue and we're using greedy. 27 | 28 | ![Screenshot from 2021-08-31 15-44-53](https://user-images.githubusercontent.com/42698268/131485875-62efe6a4-0a6e-4c51-ab23-1eb2080858fb.png) 29 | 30 | Here we can see that the node 5 is inserted two times, i.e (5, 5) and (7, 5) but only (5, 5) will be used from pri. queue because it has the shortest dist from source i.e 5 and the other one has distance 7. 31 | You can also ommit (7, 5), to do that you have to use set data structure instead of a priority queue i.e ```set>``` but deleletion doesn't will make much of a difference and priority queue is easier to implement 32 | 33 | 34 | ## Time and Space complexity 35 | 36 | * Time complexity would be ```O((N+E) + log n)```, O(N+E) for the traversing the adjacency list and logn for the priority queue 37 | * Space complexity: Apart from the adjacency list we'd have ``` O(N) + O(N)```, O(N) for the distance array and O(N) for the priority queue. 38 | 39 | ```cpp 40 | 41 | #include 42 | using namespace std; 43 | 44 | void dijkstra(int v, int src, vector> adj[]){ 45 | vector dist(v, INT_MAX); 46 | //this priority queue is representing min heap 47 | priority_queue, vector>, greater > > pq; 48 | dist[src] = 0; 49 | //push the source in your priority queue 50 | pq.push(make_pair(0, src)); 51 | //run until queue will not become empty 52 | while(!pq.empty()){ 53 | //fetch the top node from the priority queue 54 | //top element of the priority queue will have least weight 55 | int node = pq.top().second; 56 | int wt = pq.top().first; 57 | pq.pop(); 58 | //compare the distance, if distance can be updated then update it and push it in priority queue 59 | for(auto it : adj[node]){ 60 | if(dist[node] + it.second < dist[it.first]){ 61 | dist[it.first] = dist[node] + it.second; 62 | pq.push(make_pair(dist[it.first]), it.first); 63 | } 64 | } 65 | } 66 | 67 | cout<<"The distance from source to all vertices would be :"; 68 | for(int i=0; i>n>>m; 76 | 77 | //this is undirected weighted graph 78 | cout<<"Enter all the edges, i.e, start and end of node and their weight: "<> adj[n]; 80 | for(int i=0; i>u>>v>>wt; 83 | adj[u].push_back(make_pair(v, wt)); 84 | adj[v].push_back(make_pair(u, wt)); 85 | } 86 | cout<<"Enter the source of the graph: "; 87 | cin>>src; 88 | dijkstra(n, src, adj); 89 | return 0; 90 | } 91 | 92 | 93 | ``` 94 | 95 | 96 | OUTPUT: 97 | ![Screenshot from 2021-08-31 17-33-35](https://user-images.githubusercontent.com/42698268/131635392-422bef8f-2471-4c03-893b-db33f7239a38.png) 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /19.MinimumSpanningTree.md: -------------------------------------------------------------------------------- 1 | # Minimum Spanning tree 2 | * When a graph is converted into a tree such that it contains all the n nodes and only n-1 edges connecting all the nodes such that every node is reachable from every other node and the cost of that tree is minimal then that is known as the minimum spanning tree or MST 3 | * For a graph there can be multiple spanning tree. 4 | 5 | 6 | ![Screenshot from 2021-09-01 01-48-17](https://user-images.githubusercontent.com/42698268/131570233-fea49afc-efa3-4a7f-bcb8-91601913ac12.png) 7 | 8 | Now let us see the MST of one more graph: 9 | 10 | ![Screenshot from 2021-09-01 01-56-20](https://user-images.githubusercontent.com/42698268/131571340-44ba9323-347d-45d2-ba4f-39b9de30191e.png) 11 | 12 | Now how do we find the MST from a graph, so there are couple of algorithms to find out the MST: 13 | * Prims Algorithm 14 | * Kruskal's Algorithm 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /20.PrimsAlgorithmMST.md: -------------------------------------------------------------------------------- 1 | # Prims Algorithm - An algorithm to find out the minimum spanning tree from a given graph 2 | 3 | ![Screenshot from 2021-09-01 02-01-13](https://user-images.githubusercontent.com/42698268/131573432-88fe85a5-f108-4fb4-80f0-f11d10a04f50.png) 4 | 5 | This would be the MST for the above graph 6 | 7 | ![Screenshot from 2021-09-01 02-02-55](https://user-images.githubusercontent.com/42698268/131573501-63b0f1af-e50f-41d0-b37a-6d0c21785b2b.png) 8 | 9 | 10 | ## Steps: 11 | * Start from the first node 12 | 13 | ![Screenshot from 2021-09-01 02-09-47](https://user-images.githubusercontent.com/42698268/131634320-c5cd0cb9-165e-4e8f-8877-6dcd627aad22.png) 14 | 15 | 16 | * Find out the minimum edge attach to this edge 17 | 18 | ![Screenshot from 2021-09-01 02-13-05](https://user-images.githubusercontent.com/42698268/131634345-71b2f705-4034-477e-83b8-ae2b96035d37.png) 19 | 20 | 21 | * Then in the next step find out all the adjacent nodes attached to the nodes included in the mst, so these marked edges are the attached adjacent edges, now find the min. among them 22 | 23 | ![Screenshot from 2021-09-01 13-27-32](https://user-images.githubusercontent.com/42698268/131634711-504396f4-c3a3-4ce1-be89-14c1a24e7bca.png) 24 | 25 | * and then choose the one with the least edge weight 26 | 27 | ![Screenshot from 2021-09-01 13-29-40](https://user-images.githubusercontent.com/42698268/131634846-7d7668cb-8fd7-449d-b0a0-fe34f4047f98.png) 28 | 29 | 30 | * Repeat this process until total no of edges in your mst will become n-1, that is when all nodes will be connected 31 | 32 | * Click [here](https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/) for more better visual representations. 33 | 34 | ## Let us look at one more example for better understanding: 35 | 36 | PIck the starting node 37 | 38 | ![Screenshot from 2021-09-01 13-48-33](https://user-images.githubusercontent.com/42698268/131637388-41286176-4e1e-437f-8704-0ff1560a7a37.png) 39 | 40 | 41 | ![Screenshot from 2021-09-01 13-48-41](https://user-images.githubusercontent.com/42698268/131637396-9d7cf653-8cda-4213-aedf-307e1875c519.png) 42 | 43 | ![Screenshot from 2021-09-01 13-48-48](https://user-images.githubusercontent.com/42698268/131637405-1dfe8891-6340-4b61-b8ec-8cdab2bb5793.png) 44 | 45 | ![Screenshot from 2021-09-01 13-48-57](https://user-images.githubusercontent.com/42698268/131637412-344bb9ea-dd5d-48c4-84be-5734276e5332.png) 46 | Now we can see that this node 2---4 has least weight but we can't pick it as it is creating a cycle, and there can't be a cycle in MST, because the definition itself says that this is a spanning tree, so a tree cannot have a cycle. 47 | 48 | 49 | So this one will be picked: 50 | 51 | ![Screenshot from 2021-09-01 13-51-24](https://user-images.githubusercontent.com/42698268/131637716-fdd306ca-cbe6-49fd-a4f5-a076a2292b60.png) 52 | 53 | below would be the final MST of the given graph: 54 | 55 | ![Screenshot from 2021-09-01 17-33-17](https://user-images.githubusercontent.com/42698268/131668123-a4090202-a111-4f25-a0e5-093540d2652c.png) 56 | 57 | ## Steps to implement this algorithm: 58 | * Create 3 arrays of size equal to total no. of vertices i.e n 59 | * key array of type int, initialized with infinity and source initializd with 0 60 | * MST array of type bool, initialized with false 61 | * parent array of type int initialized with -1 62 | 63 | ![Screenshot from 2021-09-01 17-38-48](https://user-images.githubusercontent.com/42698268/131668748-d29ba771-34c3-4c9d-8f73-914ec947682d.png) 64 | 65 | 1. First of all we'll find out the index from key array having minimum key value, ans that would be the source, in our case it is 0th index 66 | 2. The moment you'll get the minimum possible key value, mark it as true in mst 67 | 3. check all it's adjacent nodes 68 | 4. and if that node is not marked in mst then update it's weight in key and in the parent array assign the parent name 69 | 5. Like here we'll add 0 in mst, then will got to all it's adjacent node, first is 1, 1 is not marked in mst so assign weight in key i.e 2 and assign parent, the parent of 1 is 0 so assign it in parent array, but right now don't include it in your mst. 70 | 71 | ![Screenshot from 2021-09-02 01-12-05](https://user-images.githubusercontent.com/42698268/131734103-129152c0-317d-435b-aa23-1240350f11aa.png) 72 | 73 | 6. Do this for all adjacent node 74 | 7. After doing for all adjacent nodes, find the one having the minimum weight from the key array and mark it as true in mst 75 | 8. Now find the adjacent nodes and again store their weight (if it is not include in mst) in key and parent in parent array 76 | 9. Then find out the minimum among the key array(the one which is not included in mst) and add it in mst by marking that element in mst array as true. 77 | 10. You have to stop when you'll find out that the all adjacnet nodes of the next node is already added in mst. 78 | 11. Now you just need to print the parent array as like this as parent of 0 is no one, parent of 1 is 0, parent of 3 is 0, and parent of 4 is 1. 79 | 80 | ![Screenshot from 2021-09-02 01-32-08](https://user-images.githubusercontent.com/42698268/131736503-61024fbd-8df0-475f-bab6-09baed1aaf4a.png) 81 | 82 | 83 | 84 | ## Bruteforce implementation 85 | 86 | ```cpp 87 | 88 | #include 89 | using namespace std; 90 | 91 | void prims(int v, int src, vector> adj[]){ 92 | //declare 3 arrays and initialize them 93 | int keys[v]; 94 | bool setMst[v]; 95 | int parent[v]; 96 | 97 | for(int i=0; i wt && setMst[node] == false){ 126 | keys[node] = wt; 127 | parent[node] = index; 128 | } 129 | } 130 | 131 | } 132 | //print the nodes 133 | for(int i=0; i>n>>m; 142 | vector> adj[n]; 143 | cout<<"Enter all the edges and their weight: "<>u>>v>>wt; 147 | adj[u].push_back(make_pair(v, wt)); 148 | adj[v].push_back(make_pair(u, wt)); 149 | } 150 | 151 | 152 | int src; 153 | cout<<"Enter source node: "; 154 | cin>>src; 155 | prims(n, src, adj); 156 | return 0; 157 | } 158 | 159 | 160 | 161 | ``` 162 | 163 | ## Time and space complexity: 164 | 165 | * The time complexity would be => ``` O(N^2) ```, because we have two nested loops both going from 0 to n 166 | * Space complexity: Apart from the space taken by array, O(3N) for all the 3 arrays, therefore eventually ```O(N)``` 167 | 168 | But we can optimize it using heap data structure, i.e priority queue in c++, we'll replace it with key array to store the minimum element at the top, priority queue gives minimum value in ```log n``` so it would optimize our t.c. 169 | ## Optimized implementation 170 | 171 | ```cpp 172 | //optimized implementation using heap data structure (min heap using priority queue) 173 | #include 174 | using namespace std; 175 | 176 | void prims(int v, int src, vector> adj[]){ 177 | //declare 3 arrays and initialize them 178 | int keys[v]; 179 | bool setMst[v]; 180 | int parent[v]; 181 | 182 | for(int i=0; i, vector>, greater> > pq; 189 | //initialize key of source as 0, and parent of source as -1 190 | keys[src] = 0; 191 | parent[src] = -1; 192 | //will contain pair of (key, index) 193 | pq.push(make_pair(0, 0)); 194 | 195 | // Run the loop till all the nodes have been visited 196 | // because in the brute code we checked for mstSet[node] == false while computing the minimum 197 | // but here we simply take the minimal from the priority queue, so a lot of times a node might be taken twice 198 | // hence its better to keep running till all the nodes have been taken. 199 | // try the following case: 200 | // 6 7 201 | // 0 1 5 202 | // 0 2 10 203 | // 0 3 100 204 | // 1 3 50 205 | // 1 4 200 206 | // 3 4 250 207 | // 4 5 50 208 | while(!pq.empty()){ 209 | int index = pq.top().second; 210 | pq.pop(); 211 | //mark that node as true in mst 212 | setMst[index] = true; 213 | 214 | //go to its all adjacent nodes and find out which one has the minimum weight and is not added in mst 215 | for(auto it : adj[index]){ 216 | int node = it.first; 217 | int wt = it.second; 218 | //update the key if it has the minimum weight and is not added in mst and update the parent 219 | if(keys[node] > wt && setMst[node] == false){ 220 | keys[node] = wt; 221 | parent[node] = index; 222 | //push the key and index of a node in priority queue 223 | pq.push({keys[node], node}); 224 | } 225 | } 226 | 227 | } 228 | //print the nodes 229 | for(int i=0; i>n>>m; 238 | vector> adj[n]; 239 | cout<<"Enter all the edges and their weight: "<>u>>v>>wt; 243 | adj[u].push_back(make_pair(v, wt)); 244 | adj[v].push_back(make_pair(u, wt)); 245 | } 246 | 247 | 248 | int src; 249 | cout<<"Enter source node: "; 250 | cin>>src; 251 | prims(n, src, adj); 252 | return 0; 253 | } 254 | 255 | 256 | 257 | ``` 258 | 259 | ![Screenshot from 2021-09-02 17-08-21](https://user-images.githubusercontent.com/42698268/131837329-6da7cd32-7ac3-4e5c-bec1-b628ce0c16f9.png) 260 | 261 | 262 | 263 | ## Time and space complexity: 264 | 265 | * The time complexity would be => ``` O(N+E) + O(N log N) ```, because we have two nested loops both going from 0 to n, that would make ``` O(N log N ``` by rounding off. 266 | * Space complexity: Apart from the space taken by array, O(3N) for all the 3 arrays and O(N) taken by priority queue, therefore eventually ```O(N)``` 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /23.DisjointSet.md: -------------------------------------------------------------------------------- 1 | # Disjoint set data structure or Union-Find 2 | * This is used to find out, if two nodes are given then whether they belong to same component or not 3 | * It consists of two operations, findPar() and union() operation. findPar() will help to find the parent of the node, and union() will help you to combine two components i.e union(u, v) will combine the component in which u is and the component in which v is. 4 | * Disjoint set data structure is used in Kruskal's algorithm in detecting a cycle and at lot of places in CP. 5 | 6 | 7 | 8 | 9 | * Now union means, that combining the two components such that they have common parents 10 | 11 | 12 | ### The efficient implementation of DISJOINT SET is done by Union by rank and path compression 13 | 14 | Basically we'll do the union of two components based on their rank 15 | 16 | 17 | 1. Inititally every node is parent of itself 18 | 19 | ![Screenshot from 2021-10-02 22-03-31](https://user-images.githubusercontent.com/42698268/135725073-47f35fec-50e6-4006-8991-3fad03a00ace.png) 20 | 21 | right now, if i will ask the parent of 3, then it will return 3, as every node is the parent of itself 22 | 23 | 2. And we will also maintain another array called ```rank array``` which will contain rank of all the elements, initial rank of everyone will be zero. 24 | 25 | 26 | ![Screenshot from 2021-10-02 22-11-26](https://user-images.githubusercontent.com/42698268/135725244-217655fd-d348-44dd-8a44-75299c73c445.png) 27 | 28 | 3. First of all you are asked to do the union of 1 and 2, i.e union(1, 2), therefore we will find the parent of 1 and 2, we can see the parent of 1 is 1 and parent of 2 is 2, now find out the rank of both the parents, if both of them have same rank then either attach 1 with 2 or attach 2 with 1, doesn't matter. 29 | 4. Else if both have different ranks, then attach the one having the smaller rank with the one having the greater rank. 30 | 5. and just make sure to increase the rank by 1 of the guy to whom you are attaching to, here if we'll attach 2 with 1 then increase the rank of 1 by 1 31 | 32 | ![Screenshot from 2021-10-02 22-17-42](https://user-images.githubusercontent.com/42698268/135725408-c706af7b-4da6-4b35-b1c3-685789e45138.png) 33 | 34 | 6. Now union(2, 3), so first of all find the parent of 2 and 3, as parent of 2 is 1 and parent of 3 is 3, now rank of 2's parent i.e 1 is 1 and rank of 3's parent i.e 3 is 0, as rank of 1 > rank of 3, so 3 will be attached with 1, and whenever the ranks are different, then there is no need to increase the rank 35 | 36 | ![Screenshot from 2021-10-02 22-20-37](https://user-images.githubusercontent.com/42698268/135725513-8bc27f4c-4289-41f5-b2c6-89a04813267c.png) 37 | 38 | ![Screenshot from 2021-10-02 22-20-54](https://user-images.githubusercontent.com/42698268/135725515-3dcc3434-87c1-4094-874e-e29b13370209.png) 39 | 40 | ``` 41 | Now why we aren't attaching the components directly but attaching them by comparing the ranks, the reason is that if we'll not compare the ranks and will attach directly then it will elongate the tree, increasing the depth of the tree results in increasing the time complexity of finding parent 42 | 43 | 44 | ``` 45 | something like this: 46 | 47 | ![Screenshot from 2021-10-02 22-27-29](https://user-images.githubusercontent.com/42698268/135725687-8b6cfde7-4f87-4de3-bb23-403df3b1b229.png) 48 | 49 | So this was the Union by rank, now let us see what is the path compression: 50 | 51 | Now in this case: 52 | 53 | 54 | ![Screenshot from 2021-10-02 22-32-31](https://user-images.githubusercontent.com/42698268/135725858-ab2648e6-5a4b-4a83-ac61-da8711a996f0.png) 55 | 56 | we can see that the parent of 7 is 6, and parent of 6 is 4, basically parent of 7 is 4, but we have to traverse all the way through the treeto find the final parent, so what we can do is, we can compress the path by joining the 7 directly with 4, i.e you don't need to caluclate it again and again, once you calculate that the parent of 7 is 4, then just connect 7 with 4, so that next time you don't need to calculate the parent of 7 again. 57 | 58 | similarly you can do this for all of them 59 | 60 | ![Screenshot from 2021-10-02 22-36-49](https://user-images.githubusercontent.com/42698268/135725978-ce918a91-9d18-4689-be9e-ead2465bbe8d.png) 61 | 62 | ```Path compression allows to minimize the number of movements while finding the parent of a node``` 63 | 64 | ## Time complexity and space complexity 65 | 66 | * Time complexity of performing both union() and findPar() operation together takes ```O(4 * alpha)``` which is nearly equal to ```O(4)```, therefore performing both union and find operation m times will take ```O(m * 4 * alpha)``` which is equal to ```O(m * 4)``` 67 | 68 | * Space complexity would be O(2n) as we are using a rank array and a parent array 69 | 70 | ## Code will not run, it is just for reference 71 | ```cpp 72 | 73 | /* 74 | step 1: makeSet - set each element to be its own parent and rank of each element to be 0 75 | step 2: findpar - find the ultimate parent of each element 76 | step 3: do the path compressing in findpar 77 | step 4: union - find the union of two nodes 78 | 79 | */ 80 | 81 | #include 82 | using namespace std; 83 | 84 | int rank[100000]; 85 | int par[100000]; 86 | 87 | //set each element to be its own parent and rank of each element to be 0 88 | void makeSet(){ 89 | for(int i=0; i<100000; i++){ 90 | par[i] = i; 91 | rank[i] = 0; 92 | } 93 | } 94 | 95 | //find the ultimate parent of each element 96 | int findpar(int node){ 97 | if(par[node] == node){ 98 | return node; 99 | } 100 | //path compression by storing the values 101 | return par[node] = findpar(par[node]); 102 | } 103 | 104 | //find union of two elements 105 | void union(int u, int v){ 106 | //first of all find the parent of both the elemnts 107 | u = findpar(u); 108 | v = findpar(v); 109 | 110 | //rule : smaller will attach with larger 111 | //if same rank then anybody can be attached with anyone 112 | 113 | //if the rank of the u's parent is greater then attach v with u 114 | if(rank[u]>rank[v]){ 115 | //attaching v with u, i.e set the parent of v as u 116 | par[v] = u; 117 | } 118 | 119 | //if the rank of the v's parent is greater then attach u with v 120 | else if(rank[v]>rank[u]){ 121 | //attaching u with v, i.e set the parent of u as v 122 | par[u] = v; 123 | } 124 | 125 | //if parent of both u and v have same rank then you can attach anyone with anyone 126 | else if(rank[u] == rank[v]){ 127 | //let us say I attached u with v 128 | par[u] = v; 129 | //then increase the rank of v by 1, as v is ultimate parent now 130 | rank[v]++; 131 | } 132 | } 133 | 134 | int main(){ 135 | makeSet(); 136 | int m; 137 | cin>>m; 138 | while(m--){ 139 | int u, v; 140 | cin>>u>>v; 141 | union(u, v); 142 | } 143 | 144 | //let us check if 2 and 3 belong to same component 145 | if(findpar(2) != findpar(3)){ 146 | cout<<"Different component"; 147 | }else{ 148 | cout<<"Same component"; 149 | } 150 | return 0; 151 | } 152 | 153 | ``` 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /24. Kruskal's Algorithm.md: -------------------------------------------------------------------------------- 1 | # Kruskals Algorithm 2 | ``` This algorithm is used to find the minimum spanning tree``` 3 | 4 | ![Screenshot from 2021-10-03 03-09-08](https://user-images.githubusercontent.com/42698268/135732467-58f0639c-3da1-4e9d-bae0-5040d69473bc.png) 5 | 6 | ## Steps: 7 | * Instead of creating an adjacency list, create a linear data structure to contain edges 8 | * sort the edges in ascending order 9 | * create mst vector 10 | * keep adding the edges in mst until it does not create a cycle (check cycle using union find algo of disjoint set, i.e if the starting point and ending point of edge has same parent, that does mean it is creating a cycle.) 11 | * If adding the edge creates a cycle, then don't add it and move further 12 | 13 | ## 0 Based Indexing 14 | ```cpp 15 | #include 16 | using namespace std; 17 | 18 | class node{ 19 | public: 20 | int u, v, wt; 21 | 22 | node(int first, int second, int weight){ 23 | u = first; 24 | v = second; 25 | wt = weight; 26 | } 27 | }; 28 | 29 | bool comp(node a, node b){ 30 | return a.wt &parent){ 34 | if(parent[u] == u) return u; 35 | return parent[u] = findPar(parent[u], parent); 36 | } 37 | 38 | void unionn(int u, int v, vector &parent, vector &rank){ 39 | u = findPar(u, parent); 40 | v = findPar(v, parent); 41 | 42 | if(rank[u]>rank[v]){ 43 | parent[v] = u; 44 | } 45 | else if(rank[u]>n>>m; 57 | 58 | vector edges; 59 | for(int i=0; i>u>>v>>wt; 62 | edges.push_back(node(u, v, wt)); 63 | } 64 | 65 | sort(edges.begin(), edges.end(), comp); 66 | 67 | vector parent(n); 68 | for(int i=0; i rank(n, 0); 72 | 73 | int cost=0; 74 | vector> mst; 75 | for(auto it : edges){ 76 | if(findPar(it.v, parent) != findPar(it.u, parent)){ 77 | cost += it.wt; 78 | mst.push_back({it.u, it.v}); 79 | unionn(it.u, it.v, parent, rank); 80 | } 81 | } 82 | 83 | cout<<"Cost - "<< cost< 95 | using namespace std; 96 | 97 | class node{ 98 | public: 99 | int u, v, wt; 100 | 101 | node(int first, int second, int weight){ 102 | u = first; 103 | v = second; 104 | wt = weight; 105 | } 106 | }; 107 | 108 | bool comp(node a, node b){ 109 | return a.wt &parent){ 113 | if(parent[u] == u) return u; 114 | return parent[u] = findPar(parent[u], parent); 115 | } 116 | 117 | void unionn(int u, int v, vector &parent, vector &rank){ 118 | u = findPar(u, parent); 119 | v = findPar(v, parent); 120 | 121 | if(rank[u]>rank[v]){ 122 | parent[v] = u; 123 | } 124 | else if(rank[u]>n>>m; 137 | 138 | //instead of creating an adjacency list, we will create a linear data structure of edges 139 | //type of each edge will be node, i.e will contain starting point, ending pt and weight 140 | vector edges; 141 | for(int i=0; i>u>>v>>wt; 145 | edges.push_back(node(u, v, wt)); 146 | } 147 | 148 | //sort the edges in ascending order on the basis of weight 149 | sort(edges.begin(), edges.end(), comp); 150 | 151 | //initialise parent of each node to be the node itself 152 | vector parent(n+1); 153 | for(int i=1; i<=n; i++){ 154 | parent[i] = i; 155 | } 156 | //initialise the rank of each node to be zero 157 | vector rank(n+1, 0); 158 | 159 | 160 | int cost=0; 161 | //create a mst 162 | vector> mst; 163 | for(auto it : edges){ 164 | //add the edge if it is not creating cycle 165 | /*i.e if both the starting point and ending point are not in the same component 166 | therefore not creating cycle, therefore find parent of both node */ 167 | if(findPar(it.v, parent) != findPar(it.u, parent)){ 168 | //if not creating cycle then push it in mst and add cost 169 | cost += it.wt; 170 | mst.push_back({it.u, it.v}); 171 | //now add this edge in main component 172 | unionn(it.u, it.v, parent, rank); 173 | } 174 | } 175 | 176 | //print price and mst 177 | cout<<"Cost - "<< cost<tin[node])```, if this fulfills then there is a bridge 16 | * else if the node is already visited, then update the low of node 17 | 18 | ## 0 Based Indexing 19 | ```cpp 20 | #include 21 | using namespace std; 22 | 23 | void dfs(int node, int parent, vector &vis, vector &tin, vector &low, int &timer, vector adj[]){ 24 | 25 | //mark the node as visited 26 | vis[node] = 1; 27 | //everytime a node is visited in dfs, the timer gets increased and 28 | //time of insertion and lowest of node gets updated 29 | tin[node] = low[node] = timer++; 30 | 31 | for(auto it : adj[node]){ 32 | //if the adjacent element is parent, we'll not do a dfs call because we know 33 | // that it will go backward 34 | if(it == parent) continue; 35 | 36 | if(!vis[it]){ 37 | /* call dfs for adjacent nodes, now when dfs will be called, time of insertion 38 | will increase and low of node will increase */ 39 | dfs(it, node, vis, tin, low, timer, adj); 40 | //low of the node will be updated whose dfs is completed 41 | //it will be updated only if the adjacent node have lesser low 42 | low[node] = min(low[node], low[it]); 43 | 44 | //if this condition follows that does mean that the node is visited by some other 45 | //component and not this component, therefore it is a bridge 46 | if(low[it]>tin[node]){ 47 | cout<>n>>m; 64 | vector adj[n]; 65 | for(int i=0; i>u>>v; 68 | adj[u].push_back(v); 69 | adj[v].push_back(u); 70 | } 71 | 72 | //create time of insertion for the given node 73 | //create lowest time for the given node 74 | //visited array 75 | 76 | vector tin(n, -1); 77 | vector low(n, -1); 78 | vector vis(n, 0); 79 | 80 | int timer=0; 81 | 82 | //call dfs for the whole graph, i.e all the components 83 | for(int i=0; i= tin[node]) && parent != -1)``` 40 | -------------------------------------------------------------------------------- /27.Kosaraju's Algorithm.md: -------------------------------------------------------------------------------- 1 | # Kosaraju's Algorithm 2 | Helps tto find all the strongly connected components in the directed graph 3 | 4 | ## Strongly Connected com 5 | * In strongly connected components, every node will be reachable to every other node 6 | * ![image](https://github.com/tannuchoudhary/GraphSeries/assets/42698268/e4181b05-004d-4133-aa37-95ffd6de24dc) 7 | 8 | * in the above graph G1, there are total 3 SCC(strongly connected components) first is {1, 2, 3}(order does not matter), second is {4} and third is {5}, 4 and 5 are not stronly connected bcz we can go from 4 to 5 but not from 5 to 4 9 | 10 | ## steps 11 | * You've to sort all the nodes in order of finishing time - we know that this can be only done by Topo Sort - ```O(N)``` 12 | * Transpose the graph, i.e reverse the direction if edges - ```O(N+E)``` 13 | * Do the DFS according to the finishing time, i.e whatever we have store in the stack - ```O(N+E)``` 14 | ![image](https://github.com/tannuchoudhary/GraphSeries/assets/42698268/6f1852fa-a248-436e-957c-94553c4c7aa5) 15 | 16 | * T.C = ```O(N)``` for topo sort + ```O(N +E)``` for transpose + ```O(N +E)``` for DFS = ```O(N +E)``` 17 | * S.C = ```O(N +E)``` to store the transpose graph + ```O(N)``` for visited array + ```O(N)``` for stack = ```O(N +E)``` 18 | 19 | ## code 20 | * take care when converting from vector of vector of edges to adjacency list - loop will go upto the size of the edges i.e edges.size() and not upto the size of the vertex(frequent + silly mistake) 21 | * in topo sort, the vertex will be pushed in the stack in the last 22 | ```cpp 23 | #include 24 | using namespace std; 25 | 26 | void revDfs(int src, vector &tempAns, vector &vis, vector transpose[]){ 27 | vis[src] = 1; 28 | tempAns.push_back(src); 29 | 30 | for(auto it : transpose[src]){ 31 | if(!vis[it]){ 32 | revDfs(it, tempAns, vis, transpose); 33 | } 34 | } 35 | 36 | } 37 | void topoDfs(int src, vector &vis, vector adj[], stack &st){ 38 | vis[src] = 1; 39 | for(auto it : adj[src]){ 40 | if(!vis[it]){ 41 | topoDfs(it, vis, adj, st); 42 | } 43 | 44 | } 45 | st.push(src); 46 | } 47 | vector> stronglyConnectedComponents(int n, vector> &edges) 48 | { 49 | // Write your code here. 50 | vector adj[n]; 51 | 52 | for(int i=0; i vis(n, 0); 59 | stack st; 60 | for(int i=0; i transpose[n]; 67 | 68 | for(int i=0; i> ans; 75 | int count=0; 76 | while(!st.empty()){ 77 | int node = st.top(); 78 | st.pop(); 79 | 80 | if (!vis[node]) { 81 | vector tempAns; 82 | revDfs(node, tempAns, vis, transpose); 83 | ans.push_back(tempAns); 84 | } 85 | } 86 | 87 | return ans; 88 | 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /28. Bellman Ford.md: -------------------------------------------------------------------------------- 1 | # Bellman Ford Algorithm 2 | ``` Bellman Ford is used to find the shortest path from source to all other nodes ``` 3 | ``` Dijkstra fails in case of negative edge, which was solved by bellman ford ``` 4 | Dijkstra is also used to find the shortest path between source to destination but, dijkstra does not work in the case of negative edge. Because in the case of dijkstra if you'll calculate shortest distance between two nodes, then each time they will give different weight, and it will stuck in the infinite loop. so this problem was solved by Bellman Ford Algorithm 5 | 6 | 7 | ![Screenshot from 2021-10-03 20-00-04](https://user-images.githubusercontent.com/42698268/135758430-30e8a9b9-d576-42ee-91e5-81aefa70bb39.png) 8 | 9 | * Bellman Ford will not give answer in the case of negative weight cycles, because each time you will iterate, it will give lesser answer, But ```bellman will tell you whether there is a negative weight cycle or not.``` 10 | 11 | ![Screenshot from 2021-10-03 20-05-00](https://user-images.githubusercontent.com/42698268/135758622-c442812f-ab07-437b-b752-1ceb85c7f675.png) 12 | 13 | * It will work for both undirected as well as directed graph 14 | 15 | ## Time Complexity and Space complexity 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphSeries --------------------------------------------------------------------------------