diff --git a/12_graph/01_create_and_print_graph.cpp b/12_graph/01_create_and_print_graph.cpp new file mode 100644 index 0000000..7fec43f --- /dev/null +++ b/12_graph/01_create_and_print_graph.cpp @@ -0,0 +1,59 @@ +/* + link: https://www.javatpoint.com/graph-theory-graph-representations#:~:text=In%20graph%20theory%2C%20a%20graph,to%20it%20by%20an%20edge). + + link: https://onedrive.live.com/?authkey=%21AJrTq%5FU8BPKIWDk&cid=842AECBB531CCEA4&id=842AECBB531CCEA4%211179&parId=842AECBB531CCEA4%211164&o=OneUp + +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using adjacency matrix: + + TC: O(1) => for searching + SC: O(N^2) +*/ + +int adjMatrix() { + int rows, cols; + cin >> rows >> cols; + + int adj[rows + 1][rows + 1]; + + for (int i = 0;i < rows;i++) { + int u, v; + cin >> u >> v; + adj[u][v] = 1; + adj[v][u] = 1; + } +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using adjacency list + + TC: O(Edges of that vertex) + SC: O(N + (2*E)) +*/ + +int adjList() { + int rows, cols; + cin >> rows >> cols; + + vector adj(rows + 1); + + for (int i = 0;i < m;i++) { + int u, v; + cin >> u >> v; + + adj[u].push_back(v); + adj[v].push_back(u); // comment this line for directed graph + + // for weighted graph use: adj[u].push_back({v, wt}); + // adj[v].push_back({u, wt}); + } +} \ No newline at end of file diff --git a/12_graph/02_implement_BFS_algorithm.cpp b/12_graph/02_implement_BFS_algorithm.cpp new file mode 100644 index 0000000..934dccc --- /dev/null +++ b/12_graph/02_implement_BFS_algorithm.cpp @@ -0,0 +1,90 @@ +/* + link: https://practice.geeksforgeeks.org/problems/bfs-traversal-of-graph/1 + + sol: https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/ + + video: https://youtu.be/UeE67iCK2lQ?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + travel adjacent node first + than move to the next node + + The Time complexity of BFS is O(V + E) when Adjacency List is used + and O(V^2) when Adjacency Matrix is used, + where V stands for vertices and E stands for edges. + + as it will go to every vertex as well as it will check for corresponding edges + hence TC becomes V+E +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + for connected component +*/ +vector bfsOfGraph(int V, vector adj[]) +{ + vector vis(V, false); + vector ans; + + queue q; + q.push(0); + vis[0] = 1; + + while (!q.empty()) { + int curr = q.front(); + q.pop(); + ans.push_back(curr); + + for (auto j : adj[curr]) { + if (!vis[j]) { + q.push(j); + vis[j] = 1; + } + } + } + + return ans; +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + for disconnected component + + TC: O(N + E) => visiting every node once + SC: O(N + E) => space for every node and vice-verca for both edge +*/ + +vector bfsOfGraph(int V, vector adj[]) +{ + vector vis(V, false); + vector ans; + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + int i = 0; + queue q; + q.push(i); + vis[i] = 1; + + while (!q.empty()) { + int curr = q.front(); + q.pop(); + ans.push_back(curr); + + for (auto j : adj[curr]) { + if (!vis[j]) { + q.push(j); + vis[j] = 1; + } + } + } + } + + return ans; + } +} diff --git a/12_graph/03_implement_DFS_algorithm.cpp b/12_graph/03_implement_DFS_algorithm.cpp new file mode 100644 index 0000000..3ebdeba --- /dev/null +++ b/12_graph/03_implement_DFS_algorithm.cpp @@ -0,0 +1,174 @@ +/* + link: https://practice.geeksforgeeks.org/problems/depth-first-traversal-for-a-graph/1 + + sol: https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/ + + video: https://youtu.be/uDWljP2PGmU?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + [Accepted] + + TC: O(V + E) + SC: O(V + E) +*/ +void dfs(int curr, vector adj[], vector& vis, vector& ans) { + ans.push_back(curr); + vis[curr] = 1; + + for (auto i : adj[curr]) { + if (!vis[i]) dfs(i, adj, vis, ans); + } +} + +vectordfsOfGraph(int V, vector adj[]) +{ + vector vis(V, 0); + vector ans; + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + dfs(i, adj, vis, ans); + } + } + return ans; +} + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + for connected component + + TC: O(V + E) + SC: O(V + E) +*/ + +// Graph class represents a directed graph +// using adjacency list representation +class Graph +{ +public: + map visited; + map> adj; + + // function to add an edge to graph + void addEdge(int v, int w); + + // DFS traversal of the vertices + // reachable from v + void DFS(int v); +}; + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); // Add w to v’s list. +} + +void Graph::DFS(int v) +{ + // Mark the current node as visited and + // print it + visited[v] = true; + cout << v << " "; + + // Recur for all the vertices adjacent + // to this vertex + list::iterator i; + for (i = adj[v].begin(); i != adj[v].end(); ++i) + if (!visited[*i]) + DFS(*i); +} + +// Driver code +int main() +{ + // Create a graph given in the above diagram + Graph g; + g.addEdge(0, 1); + g.addEdge(0, 9); + g.addEdge(1, 2); + g.addEdge(2, 0); + g.addEdge(2, 3); + g.addEdge(9, 3); + + cout << "Following is Depth First Traversal" + " (starting from vertex 2) \n"; + g.DFS(2); + + return 0; +} + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + for disconnected component + + TC: O(V + E) + SC: O(V + E) +*/ +class Graph { + + // A function used by DFS + void DFSUtil(int v); + +public: + map visited; + map> adj; + // function to add an edge to graph + void addEdge(int v, int w); + + // prints DFS traversal of the complete graph + void DFS(); +}; + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); // Add w to v’s list. +} + +void Graph::DFSUtil(int v) +{ + // Mark the current node as visited and print it + visited[v] = true; + cout << v << " "; + + // Recur for all the vertices adjacent to this vertex + list::iterator i; + for (i = adj[v].begin(); i != adj[v].end(); ++i) + if (!visited[*i]) + DFSUtil(*i); +} + +// The function to do DFS traversal. It uses recursive +// DFSUtil() +void Graph::DFS() +{ + // Call the recursive helper function to print DFS + // traversal starting from all vertices one by one + for (auto i : adj) + if (visited[i.first] == false) + DFSUtil(i.first); +} + +// Driver Code +int main() +{ + // Create a graph given in the above diagram + Graph g; + g.addEdge(0, 1); + g.addEdge(0, 9); + g.addEdge(1, 2); + g.addEdge(2, 0); + g.addEdge(2, 3); + g.addEdge(9, 3); + + cout << "Following is Depth First Traversal \n"; + g.DFS(); + + return 0; +} diff --git a/12_graph/04_detect_cycle_in_directed_graph_using_DFS_BFS.cpp b/12_graph/04_detect_cycle_in_directed_graph_using_DFS_BFS.cpp new file mode 100644 index 0000000..0923ac2 --- /dev/null +++ b/12_graph/04_detect_cycle_in_directed_graph_using_DFS_BFS.cpp @@ -0,0 +1,111 @@ +/* + link: https://practice.geeksforgeeks.org/problems/detect-cycle-in-a-directed-graph/1 + + sol (using DFS): https://www.geeksforgeeks.org/detect-cycle-in-a-graph/ + sol (using BFS): https://www.geeksforgeeks.org/detect-cycle-in-a-directed-graph-using-bfs/ + + video (using DFS): https://youtu.be/uzVUw90ZFIg?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + video (using BFS or kahn's algo): https://youtu.be/V6GxfKDyLBM?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + here cycle means + 1. node must be visited + 2. whole cycle loop must have same direction of edges + + so previous algo. of undirected graph won't work here +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using DFS + + TC: O(N + E) // N or V both are same (vertices) + SC: O(N + E) +*/ +bool checkCycle(int curr, vector& vis, vector& dfsVis, vector adj[]) { + // to record that we have visited + vis[curr] = 1; + // to record that current vertex is visited and is in current movement/direction + dfsVis[curr] = 1; + for (auto i : adj[curr]) { + if (!vis[i]) { + /* + hence here dont write "return checkCycle().." as if false we will check for other nodes + as well + */ + if (checkCycle(i, vis, dfsVis, adj)) return true; + } + // it is cycle only if node is visited once as well as it is in current movement/direction + else if (dfsVis[i]) return true; + } + // when we r recurring back reset our current movement dfsVis + dfsVis[curr] = 0; + return false; +} +bool isCyclic(int V, vectoradj[]) +{ + // to record if node is visited or not (help in disconnected component) + vector vis(V, 0); + + // to record the visited node in current movement/direction + vector dfsVis(V, 0); + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + if (checkCycle(i, vis, dfsVis, adj)) return true; + } + } + return false; +} + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + ref: 13/implement_topological_sort using BFS (kahn's algo) + + using BFS (kahn's algorithm) + TC: O(V + E) + SC: O(V) + O(V) -> 1st for inDeg, 2nd for queue +*/ +bool isCyclic(int V, vector adj[]) +{ + vector inDeg(V, 0); + + for (int i = 0; i < V; i++) { + for (auto k : adj[i]) { + inDeg[k]++; + } + } + + queue q; + + for (int i = 0;i < V;i++) { + if (inDeg[i] == 0) q.push(i); + } + + int cnt = 0; + + while (!q.empty()) { + int curr = q.front(); + q.pop(); + cnt++; // instead of storing we are maintaining count record + + for (auto i : adj[curr]) { + inDeg[i]--; + // if i ele. became + if (inDeg[i] == 0) q.push(i); + } + } + + /* + if the count of the node arranged topologically is V then for sure it + does n't have cycle as topological sort works for only DAG + or if it doesn't get equal to V no. of vertices means cycle + would have been detected somewhere + */ + if (cnt == V) return false; + return true; +} \ No newline at end of file diff --git a/12_graph/05_detect_cycle_in_undirected_graph_using_DFS_BFS.cpp b/12_graph/05_detect_cycle_in_undirected_graph_using_DFS_BFS.cpp new file mode 100644 index 0000000..784fd05 --- /dev/null +++ b/12_graph/05_detect_cycle_in_undirected_graph_using_DFS_BFS.cpp @@ -0,0 +1,86 @@ +/* + link: https://practice.geeksforgeeks.org/problems/detect-cycle-in-an-undirected-graph/1 + + sol: https://www.geeksforgeeks.org/detect-cycle-undirected-graph/ + sol (using bfs): https://www.geeksforgeeks.org/detect-cycle-in-an-undirected-graph-using-bfs/ + + video (using BFS): https://youtu.be/A8ko93TyOns?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + video (using DFS): https://youtu.be/Y9NFqI6Pzd4?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS + + TC: O(V + E) + SC: O(V + E) +*/ +bool checkCycle(int curr, vector& vis, vector adj[]) { + vis[curr] = 1; + + queue> q; + q.push({ curr, -1 }); + + while (!q.empty()) { + pair p = q.front(); + q.pop(); + + for (auto i : adj[p.first]) { + if (!vis[i]) { + vis[i] = 1; + q.push({ i, p.first }); + } + else if (i != p.second) return true; + } + } + return false; +} +bool isCycle(int V, vectoradj[]) +{ + vector vis(V, 0); + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + if (checkCycle(i, vis, adj)) return true; + } + } + return false; +} + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using DFS + + TC: O(N + E) // N or V both are same (vertices) + SC: O(N + E) +*/ +bool checkCycle(int curr, int prev, vector& vis, vector adj[]) { + vis[curr] = 1; + + for (auto i : adj[curr]) { + if (!vis[i]) { + /* + hence here dont write "return checkCycle().." as if false we will check for other nodes + as well + */ + if (checkCycle(i, curr, vis, adj)) return true; + } + // i is visited as well as it is not parent means it is cycle + else if (i != prev) return true; + } + return false; +} +bool isCycle(int V, vectoradj[]) +{ + vector vis(V, 0); + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + if (checkCycle(i, -1, vis, adj)) return true; + } + } + return false; +} \ No newline at end of file diff --git a/12_graph/06_search_in_maze.cpp b/12_graph/06_search_in_maze.cpp new file mode 100644 index 0000000..2f85081 --- /dev/null +++ b/12_graph/06_search_in_maze.cpp @@ -0,0 +1,3 @@ +/* + ref: backtracking/1_rat_in_maze +*/ \ No newline at end of file diff --git a/12_graph/07_minimum_step_by_knight.cpp b/12_graph/07_minimum_step_by_knight.cpp new file mode 100644 index 0000000..96320af --- /dev/null +++ b/12_graph/07_minimum_step_by_knight.cpp @@ -0,0 +1,170 @@ +/* + link: https://practice.geeksforgeeks.org/problems/steps-by-knight5927/1 + + sol: https://www.geeksforgeeks.org/minimum-steps-reach-target-knight/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N^2) + SC: O(N^2) +*/ +// C++ program to find minimum steps to reach to +// specific cell in minimum moves by Knight +#include +using namespace std; + +// structure for storing a cell's data +struct cell { + int x, y; + int dis; + cell() {} + cell(int x, int y, int dis) + : x(x), y(y), dis(dis) + { + } + /* we can also use this (implicit pointer) for value updation + cell(int x, int y, int dis) + { + this->x = x; + this->y = y; + this->dis = dis; + } + */ +}; + +// Utility method returns true if (x, y) lies +// inside Board +bool isInside(int x, int y, int N) +{ + if (x >= 1 && x <= N && y >= 1 && y <= N) + return true; + return false; +} + +// Method returns minimum step +// to reach target position +int minStepToReachTarget( + int knightPos[], int targetPos[], + int N) +{ + // x and y direction, where a knight can move + int dx[] = { -2, -1, 1, 2, -2, -1, 1, 2 }; + int dy[] = { -1, -2, -2, -1, 1, 2, 2, 1 }; + + // queue for storing states of knight in board + queue q; + + // push starting position of knight with 0 distance + q.push(cell(knightPos[0], knightPos[1], 0)); + + cell t; + int x, y; + bool visit[N + 1][N + 1]; + + // make all cell unvisited + for (int i = 1; i <= N; i++) + for (int j = 1; j <= N; j++) + visit[i][j] = false; + + // visit starting state + visit[knightPos[0]][knightPos[1]] = true; + + // loop untill we have one element in queue + while (!q.empty()) { + t = q.front(); + q.pop(); + + // if current cell is equal to target cell, + // return its distance + if (t.x == targetPos[0] && t.y == targetPos[1]) + return t.dis; + + // loop for all reachable states + for (int i = 0; i < 8; i++) { + x = t.x + dx[i]; + y = t.y + dy[i]; + + // If reachable state is not yet visited and + // inside board, push that state into queue + if (isInside(x, y, N) && !visit[x][y]) { + visit[x][y] = true; + q.push(cell(x, y, t.dis + 1)); + } + } + } +} + +// Driver code to test above methods +int main() +{ + int N = 30; + int knightPos[] = { 1, 1 }; + int targetPos[] = { 30, 30 }; + cout << minStepToReachTarget(knightPos, targetPos, N); + return 0; +} + + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// [accepted] +bool isValid(int x, int y, int N) { + if (x >= 1 && x <= N && y >= 1 && y <= N) { + return true; + } + return false; +} + +struct cell { + int x, y; + int dis; + cell() {} + cell(int x, int y, int dis) + { + this->x = x; + this->y = y; + this->dis = dis; + } +}; + +int minStepToReachTarget(vector& KnightPos, vector& TargetPos, int N) +{ + int dx[] = { -2, -1, 1, 2, -2, -1, 1, 2 }; + int dy[] = { -1, -2, -2, -1, 1, 2, 2, 1 }; + + queue q; + q.push(cell(KnightPos[0], KnightPos[1], 0)); + + cell t; + int x, y; + + vector> vis(N + 1, vector(N + 1, false)); + + vis[KnightPos[0]][KnightPos[1]] = true; + + while (!q.empty()) { + t = q.front(); + q.pop(); + + if (t.x == TargetPos[0] && t.y == TargetPos[1]) return t.dis; + + for (int i = 0;i < 8;i++) { + x = t.x + dx[i]; + y = t.y + dy[i]; + + if (isValid(x, y, N) && !vis[x][y]) { + vis[x][y] = true; + q.push(cell(x, y, t.dis + 1)); + } + } + } +} \ No newline at end of file diff --git a/12_graph/08_flood_fill_algo.cpp b/12_graph/08_flood_fill_algo.cpp new file mode 100644 index 0000000..3a126ae --- /dev/null +++ b/12_graph/08_flood_fill_algo.cpp @@ -0,0 +1,45 @@ +/* + link: https://leetcode.com/problems/flood-fill/ +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +// to iterate direction +int dx[4] = { 1, -1, 0, 0 }; +int dy[4] = { 0, 0, 1, -1 }; + + +// to check if given corr. is in bound or not +bool isValid(int x, int y, int row, int col, vector>& vis) { + if (x >= 0 && x < row && y >= 0 && y < col && !vis[x][y]) return true; + return false; +} + +void dfs(int currX, int currY, int newColor, vector>& image, vector>& vis, int row, int col, int sr, int sc) { + vis[currX][currY] = 1; + + // to go in all possible direction + for (int i = 0;i < 4;i++) { + int x = currX + dx[i]; + int y = currY + dy[i]; + + // not visited, same color as given at source time, inbound => hence go for dfs + if (isValid(x, y, row, col, vis) && image[sr][sc] == image[x][y]) { + image[x][y] = newColor; + dfs(x, y, newColor, image, vis, row, col, sr, sc); + } + } +} + +vector> floodFill(vector>& image, int sr, int sc, int newColor) { + int row = image.size(); + int col = image[0].size(); + vector> vis(row, vector(col, 0)); + + dfs(sr, sc, newColor, image, vis, row, col, sr, sc); + + // also color the source after flood filling all :) + image[sr][sc] = newColor; + + return image; +} diff --git a/12_graph/09_clone_a_graph.cpp b/12_graph/09_clone_a_graph.cpp new file mode 100644 index 0000000..661133c --- /dev/null +++ b/12_graph/09_clone_a_graph.cpp @@ -0,0 +1,64 @@ +/* + link: https://leetcode.com/problems/clone-graph/ + + video: https://youtu.be/jWf5F_shzho +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using DFS +*/ +void dfs(Node* node, Node* prev, vector& vis) { + // record in vis array + vis[prev->val] = prev; + + for (auto curr : node->neighbors) { + // if not visited + if (vis[curr->val] == NULL) { + // make new node + Node* newNode = new Node(curr->val); + + // save in neighbour of prev + (prev->neighbors).push_back(newNode); + + // do dfs in both + dfs(curr, newNode, vis); + } + else { + // visited then push the address of visited in prev's neighbors + (prev->neighbors).push_back(vis[curr->val]); + } + } +} + +Node* cloneGraph(Node* node) { + if (!node) return NULL; + + vector vis(1000, NULL); + Node* newNode = new Node(node->val); + + dfs(node, newNode, vis); + + return newNode; +} + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using map +*/ +unordered_map mp; + +Node* cloneGraph(Node* node) { + if (node && !mp[node]) { + mp[node] = new Node(node->val); + for (auto i : node->neighbors) { + mp[node]->neighbors.push_back(cloneGraph(i)); + } + } + return mp[node]; +} \ No newline at end of file diff --git a/12_graph/0_graph.cpp b/12_graph/0_graph.cpp new file mode 100644 index 0000000..723c434 --- /dev/null +++ b/12_graph/0_graph.cpp @@ -0,0 +1,40 @@ +/* + link: https://youtu.be/LCrovIMurxY?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + link: https://youtu.be/I6v0itcISSY?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + graph is data-structure with 2 component: vertex and edge + + types of graph: + => there can be multiple paths in the graph + + 1. undirected graph: + -> directonless edge + -> we can come forth and back from vertex + -> here degree(vertex) means how many other vertex are connected or edges does it have + -> total of degrees = 2 * E + + 2. directed graph: + -> with direction edge + -> we can go from given vertex's direction to + -> we can write a->b and not b->a if it is directed from a to b + -> here indegree(vertex) means how many edge are coming towards the vertex, + outdegree(vertex) means how many edge are going from vertex to other vertex + + 3. undirected cyclic graph: + contains cycle + + 4. directed cyclic graph: + 5. directed acyclic graph + + 6. weighted directed graph + 7. weighted undirected graph + + + => whenever u see three different island formed in graph + it's called disconnected graph with multiple component + + for such problem one has to maintain the visited array to checkout all the component + 1. all the vertex of one component will be traversed + 2. then all the vertex of the other component will be traversed + +*/ \ No newline at end of file diff --git a/12_graph/10_making_wired_connections.cpp b/12_graph/10_making_wired_connections.cpp new file mode 100644 index 0000000..29c56cc --- /dev/null +++ b/12_graph/10_making_wired_connections.cpp @@ -0,0 +1,44 @@ +/* + link: https://leetcode.com/problems/number-of-operations-to-make-network-connected/ + + just count the disconnected graph +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +void dfs(int curr, vector v[], vector& vis) { + vis[curr] = 1; + + for (auto i : v[curr]) { + if (!vis[i]) { + dfs(i, v, vis); + } + } +} + +int makeConnected(int n, vector>& connections) { + // if cables(edges) is less than vertex-1 means all computer(vertex) won't connect + if (connections.size() < n - 1) return -1; + + vector vis(n, 0); + + vector v[n]; + + for (int i = 0;i < connections.size();i++) { + v[connections[i][0]].push_back(connections[i][1]); + v[connections[i][1]].push_back(connections[i][0]); + } + + int disconnected = 0; + + for (int i = 0;i < n;i++) { + if (!vis[i]) { + disconnected++; + dfs(i, v, vis); + } + } + + // dis -1 as initial network wont count + // the one out of which we will provide cable + return disconnected - 1; +} \ No newline at end of file diff --git a/12_graph/11_word_ladder.cpp b/12_graph/11_word_ladder.cpp new file mode 100644 index 0000000..0a8794b --- /dev/null +++ b/12_graph/11_word_ladder.cpp @@ -0,0 +1,82 @@ +/* + link: https://leetcode.com/problems/word-ladder/ + + video (just to understand the concept): https://youtu.be/ZVJ3asMoZ18 + + code given in video has O(N * L * logN * 26) + see at this time: https://youtu.be/ZVJ3asMoZ18?t=972 + + but in my code below if we use hashing for storing the complexity will be same +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: + N: size of wordList + L: size of each word + + both while loop: O(N) => as iterating every vertex once + diffByOneLetter(): O(N * L) + => as we r maintaining vis array so it will make sure all word are visited once + + + so overall time complexity: O(N * N * L) + +*/ +vector diffByOneLetter(string curr, vector& vis, vector& wordList) { + vector idx; + + for (int i = 0;i < wordList.size();i++) { + if (!vis[i]) { + int c = 0; + int cnt = 0; + while (c < curr.size()) { + if (curr[c] != wordList[i][c]) cnt++; + c++; + } + // words which are diff. by 1 letter + if (cnt == 1) { + idx.push_back(i); + vis[i] = 1; + } + } + } + + return idx; +} + +int ladderLength(string beginWord, string endWord, vector& wordList) { + vector vis(wordList.size(), 0); + + queue q; + q.push(beginWord); + + int level = 1; + + while (!q.empty()) { + int size = q.size(); + + // iterating by level + while (size--) { + string curr = q.front(); + q.pop(); + + // endWord is not present + if (curr == endWord) { + return level; + } + + vector idx = diffByOneLetter(curr, vis, wordList); + + for (auto i : idx) q.push(wordList[i]); + } + + // words with just diff from current q have been visited + level++; + } + + // endword was not reachable or wasn't present + return 0; +} \ No newline at end of file diff --git a/12_graph/12_dijkstra_algo.cpp b/12_graph/12_dijkstra_algo.cpp new file mode 100644 index 0000000..a11adfa --- /dev/null +++ b/12_graph/12_dijkstra_algo.cpp @@ -0,0 +1,61 @@ +/* + sol: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/ + + video: https://youtu.be/jbhuqIASjoM?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O((V + E) * logV) => log V for insertion in priority_queue + SC: O(V) + O(V), for distTo and priority_queue +*/ +#include +using namespace std; + +typedef pair pii; + +int main() { + int n, m, source; + cin >> n >> m; + vector g[n + 1]; // 1-indexed adjacency list for of graph + + int a, b, wt; + for (int i = 0; i < m; i++) { + cin >> a >> b >> wt; + g[a].push_back(make_pair(b, wt)); + g[b].push_back(make_pair(a, wt)); + } + + cin >> source; + + // Dijkstra's algorithm begins from here + priority_queue, greater > pq;// min-heap ; In pair => (dist,from) + vector distTo(n + 1, INT_MAX); // 1-indexed array for calculating shortest paths; + + distTo[source] = 0; + pq.push(make_pair(0, source)); // (dist,from) + + while (!pq.empty()) { + int dist = pq.top().first; + int curr = pq.top().second; + pq.pop(); + + vector::iterator it; + for (auto it : g[curr]) { + int next = it.first; + int nextDist = it.second; + if (distTo[next] > distTo[curr] + nextDist) { + distTo[next] = distTo[curr] + nextDist; + pq.push(make_pair(distTo[next], next)); + } + } + + } + + cout << "The distances from source, " << source << ", are : \n"; + for (int i = 1; i <= n; i++) cout << distTo[i] << " "; + cout << "\n"; + + return 0; +} \ No newline at end of file diff --git a/12_graph/13_implement_topological_sort.cpp b/12_graph/13_implement_topological_sort.cpp new file mode 100644 index 0000000..9136e46 --- /dev/null +++ b/12_graph/13_implement_topological_sort.cpp @@ -0,0 +1,115 @@ +/* + what is topological sorting ? + (DFS) https://www.geeksforgeeks.org/topological-sorting/ + (BFS) https://www.geeksforgeeks.org/topological-sorting-indegree-based-solution/ + + topological sort is not for cyclic graph (as it won't be possible) + so it is always for **directed** **acyclic** graph + hence ""DAG"" + + Topological sorting for Directed Acyclic Graph (DAG) is a linear + ordering of vertices such that for every directed edge u v, + vertex u comes before v in the ordering. Topological Sorting for a + graph is not possible if the graph is not a DAG. + + link: https://practice.geeksforgeeks.org/problems/topological-sort/1 + + video (DFS): https://youtu.be/Yh6EFazXipA?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + video (BFS): https://youtu.be/rZv_jHZva34?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + DFS + TC: O(V + E) + SC: O(V) + O(V) => 1st -> visited array and 2nd -> stack + ASC (auxiliary): O(V) + + here stack will ensure that all the directed nodes are visited and nothing's + left so now push element into the stack + + hence stack will have ele. in topological order +*/ +void dfs(int curr, stack& s, vector& vis, vector adj[]) { + vis[curr] = 1; + + for (auto i : adj[curr]) { + if (!vis[i]) { + dfs(i, s, vis, adj); + } + } + + s.push(curr); +} + +vector topoSort(int V, vector adj[]) +{ + vector vis(V, 0); + stack s; + + for (int i = 0;i < V;i++) { + if (!vis[i]) { + dfs(i, s, vis, adj); + } + } + + vector sorted; + while (!s.empty()) { + sorted.push_back(s.top()); + s.pop(); + } + return sorted; +} + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS (kahn's algorithm) + here we will require inDeg vector as we won't have recursive calls + so to check every time which vertex has how many indegree + + TC: O(V + E) + SC: O(V) + O(V) -> 1st for inDeg, 2nd for queue +*/ +vector topoSort(int V, vector adj[]) +{ + vector inDeg(V, 0); + + // store indegrees of all + for (int i = 0; i < V; i++) { + for (auto k : adj[i]) { + inDeg[k]++; + } + } + + queue q; + + // get all the node with indegree=0, + // if there is no node with indegree=0, means it has cycle + // if there is cycle then topological sort doesn't exist + for (int i = 0;i < V;i++) { + if (inDeg[i] == 0) q.push(i); + } + + vector topoSorted; + while (!q.empty()) { + int curr = q.front(); + q.pop(); + topoSorted.push_back(curr); + + for (auto i : adj[curr]) { + inDeg[i]--; + // if i ele. became + if (inDeg[i] == 0) q.push(i); + } + } + + return topoSorted; +} diff --git a/12_graph/14_Minimum_time_taken_by_each_job_to_be_completed_given_by_a_Directed_Acyclic_Graph.cpp b/12_graph/14_Minimum_time_taken_by_each_job_to_be_completed_given_by_a_Directed_Acyclic_Graph.cpp new file mode 100644 index 0000000..22d09d3 --- /dev/null +++ b/12_graph/14_Minimum_time_taken_by_each_job_to_be_completed_given_by_a_Directed_Acyclic_Graph.cpp @@ -0,0 +1,125 @@ +/* + Note: whenever question says pre-requisite or to complete some task before some task use topological sort + + link: https://www.geeksforgeeks.org/minimum-time-taken-by-each-job-to-be-completed-given-by-a-directed-acyclic-graph/ + + read the Approach in link +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(V + E) + SC: O(V) +*/ + +// C++ program for the above approach +#include +using namespace std; +#define maxN 100000 + +// Adjacency List to store the graph +vector graph[maxN]; + +// Array to store the in-degree of node +int indegree[maxN]; + +// Array to store the time in which +// the job i can be done +int job[maxN]; + +// Function to add directed edge +// between two vertices +void addEdge(int u, int v) +{ + // Insert edge from u to v + graph[u].push_back(v); + + // Increasing the indegree + // of vertex v + indegree[v]++; +} + +// Function to find the minimum time +// needed by each node to get the task +void printOrder(int n, int m) +{ + // Find the topo sort order + // using the indegree approach + + // Queue to store the + // nodes while processing + queue q; + + // Pushing all the vertex in the + // queue whose in-degree is 0 + + // Update the time of the jobs + // who don't require any job to + // be completed before this job + for (int i = 1; i <= n; i++) { + if (indegree[i] == 0) { + q.push(i); + job[i] = 1; + } + } + + // Iterate until queue is empty + while (!q.empty()) { + + // Get front element of queue + int cur = q.front(); + + // Pop the front element + q.pop(); + + for (int adj : graph[cur]) { + + // Decrease in-degree of + // the current node + indegree[adj]--; + + // Push its adjacent elements + // it means all the required jobs to finish before this job are finished + if (indegree[adj] == 0) { + job[adj] = job[cur] + 1; + q.push(adj); + } + } + } + + // Print the time to complete + // the job + for (int i = 1; i <= n; i++) + cout << job[i] << " "; + cout << "\n"; +} + +// Driver Code +int main() +{ + // Given Nodes N and edges M + int n, m; + n = 10; + m = 13; + + // Given Directed Edges of graph + addEdge(1, 3); + addEdge(1, 4); + addEdge(1, 5); + addEdge(2, 3); + addEdge(2, 8); + addEdge(2, 9); + addEdge(3, 6); + addEdge(4, 6); + addEdge(4, 8); + addEdge(5, 8); + addEdge(6, 7); + addEdge(7, 8); + addEdge(8, 10); + + // Function Call + printOrder(n, m); + return 0; +} diff --git a/12_graph/15_Find_whether_it_is_possible_to_finish_all_tasks_or_not_from_given_dependencies.cpp b/12_graph/15_Find_whether_it_is_possible_to_finish_all_tasks_or_not_from_given_dependencies.cpp new file mode 100644 index 0000000..f132ae3 --- /dev/null +++ b/12_graph/15_Find_whether_it_is_possible_to_finish_all_tasks_or_not_from_given_dependencies.cpp @@ -0,0 +1,144 @@ +/* + link: https://www.geeksforgeeks.org/find-whether-it-is-possible-to-finish-all-tasks-or-not-from-given-dependencies/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using DFS +*/ +// CPP program to check whether we can finish all +// tasks or not from given dependencies. +#include +using namespace std; + +// Returns adjacency list representation from a list +// of pairs. +vector > make_graph(int numTasks, + vector >& prerequisites) +{ + vector > graph(numTasks); + for (auto pre : prerequisites) + graph[pre.second].insert(pre.first); + return graph; +} + +// A DFS based function to check if there is a cycle +// in the directed graph. +bool dfs_cycle(vector >& graph, int node, + vector& onpath, vector& visited) +{ + if (visited[node]) + return false; + onpath[node] = visited[node] = true; + for (int neigh : graph[node]) + if (onpath[neigh] || dfs_cycle(graph, neigh, onpath, visited)) + return true; + return onpath[node] = false; +} + +// Main function to check whether possible to finish all tasks or not +bool canFinish(int numTasks, vector >& prerequisites) +{ + vector > graph = make_graph(numTasks, prerequisites); + vector onpath(numTasks, false), visited(numTasks, false); + for (int i = 0; i < numTasks; i++) + if (!visited[i] && dfs_cycle(graph, i, onpath, visited)) + return false; + return true; +} + +int main() +{ + int numTasks = 4; + + vector > prerequisites; + + // for prerequisites: [[1, 0], [2, 1], [3, 2]] + + prerequisites.push_back(make_pair(1, 0)); + prerequisites.push_back(make_pair(2, 1)); + prerequisites.push_back(make_pair(3, 2)); + if (canFinish(numTasks, prerequisites)) { + cout << "Possible to finish all tasks"; + } + else { + cout << "Impossible to finish all tasks"; + } + + return 0; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS +*/ +// A BFS based solution to check if we can finish +// all tasks or not. This solution is mainly based +// on Kahn's algorithm. +#include +using namespace std; + +// Returns adjacency list representation from a list +// of pairs. +vector > make_graph(int numTasks, + vector >& prerequisites) +{ + vector > graph(numTasks); + for (auto pre : prerequisites) + graph[pre.second].insert(pre.first); + return graph; +} + +// Finds in-degree of every vertex +vector compute_indegree(vector >& graph) +{ + vector degrees(graph.size(), 0); + for (auto neighbors : graph) + for (int neigh : neighbors) + degrees[neigh]++; + return degrees; +} + +// Main function to check whether possible to finish all tasks or not +bool canFinish(int numTasks, vector >& prerequisites) +{ + vector > graph = make_graph(numTasks, prerequisites); + vector degrees = compute_indegree(graph); + for (int i = 0; i < numTasks; i++) { + int j = 0; + for (; j < numTasks; j++) + if (!degrees[j]) + break; + if (j == numTasks) + return false; + degrees[j] = -1; + for (int neigh : graph[j]) + degrees[neigh]--; + } + return true; +} + +int main() +{ + int numTasks = 4; + vector > prerequisites; + prerequisites.push_back(make_pair(1, 0)); + prerequisites.push_back(make_pair(2, 1)); + prerequisites.push_back(make_pair(3, 2)); + if (canFinish(numTasks, prerequisites)) { + cout << "Possible to finish all tasks"; + } + else { + cout << "Impossible to finish all tasks"; + } + + return 0; +} diff --git a/12_graph/16_find_no_of_islands.cpp b/12_graph/16_find_no_of_islands.cpp new file mode 100644 index 0000000..f9f7802 --- /dev/null +++ b/12_graph/16_find_no_of_islands.cpp @@ -0,0 +1,58 @@ +/* + link: https://practice.geeksforgeeks.org/problems/find-the-number-of-islands/1 + + sol: https://www.geeksforgeeks.org/find-number-of-islands/ + [just refer it] [used visited array] +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N * N) => visiting every vertex only once + but if we consider checking it as well than 8^(N^2) + + SC: O(1) +*/ +int dx[8] = { 1, -1, 0, 0, 1, 1, -1, -1 }; +int dy[8] = { 0, 0, 1, -1, 1, -1, 1, -1 }; + +bool isValid(int x, int y, int row, int col, vector>& grid) { + if (x >= 0 && x < row && y >= 0 && y < col && grid[x][y] == '1') return true; + return false; +} + +void dfs(int x, int y, vector>& grid, int row, int col) { + grid[x][y] = '0'; + + for (int i = 0;i < 8;i++) { + int xx = x + dx[i]; + int yy = y + dy[i]; + + if (isValid(xx, yy, row, col, grid)) { + dfs(xx, yy, grid, row, col); + } + } +} + +int numIslands(vector>& grid) +{ + int row = grid.size(); + int col = grid[0].size(); + + int cnt = 0; + + for (int i = 0;i < row;i++) { + for (int j = 0;j < col;j++) { + if (grid[i][j] == '1') { + // means we r on new island + // if it was not new island then in prev. dfs it would have already visited + cnt++; + dfs(i, j, grid, row, col); + } + } + } + + return cnt; +} \ No newline at end of file diff --git a/12_graph/17_given_sorted_alien_dictionary_find_the_order_of_character.cpp b/12_graph/17_given_sorted_alien_dictionary_find_the_order_of_character.cpp new file mode 100644 index 0000000..767284f --- /dev/null +++ b/12_graph/17_given_sorted_alien_dictionary_find_the_order_of_character.cpp @@ -0,0 +1,60 @@ +/* + link: https://practice.geeksforgeeks.org/problems/alien-dictionary/1 + + sol: https://www.geeksforgeeks.org/given-sorted-dictionary-find-precedence-characters/ + + video: https://youtu.be/wMMwRK-w0r4 + + steps: + 1. form graph from given words by comparing (as given they are sorted) + 2. so form graph such that word from smaller to larger forms edge + 3. find topological sort + + that's it +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N + K) + O(N + K), first for forming graph and second for dfs + Note that there would be K vertices and at-most (N-1) edges in the graph. +*/ +void dfs(int curr, string& ans, vector& vis, vector>& g) { + vis[curr] = 1; + + for (auto i : g[curr]) { + if (!vis[i]) { + dfs(i, ans, vis, g); + } + } + ans += (curr + 'a'); +} + +string findOrder(string dict[], int N, int K) { + vector> g(K); + + for (int i = 0;i < N - 1;i++) { + string a = dict[i]; + string b = dict[i + 1]; + + for (int j = 0;j < min(a.size(), b.size());j++) { + if (a[j] != b[j]) { + g[a[j] - 'a'].push_back(b[j] - 'a'); + break; + } + } + } + + vector vis(K, 0); + string ans = ""; + + for (int i = 0;i < K;i++) { + if (!vis[i]) { + dfs(i, ans, vis, g); + } + } + reverse(ans.begin(), ans.end()); + return ans; +} \ No newline at end of file diff --git a/12_graph/18_implement_kruskals_algorithm.cpp b/12_graph/18_implement_kruskals_algorithm.cpp new file mode 100644 index 0000000..37519c9 --- /dev/null +++ b/12_graph/18_implement_kruskals_algorithm.cpp @@ -0,0 +1,78 @@ +/* + sol: https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/ + + video: https://youtu.be/1KRmCzBl_mQ?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + E is the edges + + TC: O(E logE) + O(E * (4*alpha)) => 1st for sorting, 2nd for checking whether it belong to same component or not + SC: O(E) + O(V) + O(V) => 1st for sorted array, 2nd for parent, 3rd for rank +*/ +#include +using namespace std; +struct node { + int u; + int v; + int wt; + node(int first, int second, int weight) { + u = first; + v = second; + wt = weight; + } +}; + +bool comp(node a, node b) { + return a.wt < b.wt; +} + +int findPar(int u, vector& parent) { + if (u == parent[u]) return u; + return parent[u] = findPar(parent[u], parent); +} + +void unionn(int u, int v, vector& parent, vector& rank) { + u = findPar(u, parent); + v = findPar(v, parent); + if (rank[u] < rank[v]) { + parent[u] = v; + } + else if (rank[v] < rank[u]) { + parent[v] = u; + } + else { + parent[v] = u; + rank[u]++; + } +} +int main() { + int N, m; + cin >> N >> m; + vector edges; + for (int i = 0;i < m;i++) { + int u, v, wt; + cin >> u >> v >> wt; + edges.push_back(node(u, v, wt)); + } + sort(edges.begin(), edges.end(), comp); + + vector parent(N); + for (int i = 0;i < N;i++) + parent[i] = i; + vector rank(N, 0); + + int cost = 0; + vector> mst; + for (auto it : edges) { + if (findPar(it.v, parent) != findPar(it.u, parent)) { + cost += it.wt; + mst.push_back({ it.u, it.v }); + unionn(it.u, it.v, parent, rank); + } + } + cout << cost << endl; + for (auto it : mst) cout << it.first << " - " << it.second << endl; + return 0; +} diff --git a/12_graph/19_implement_prims_algorithm.cpp b/12_graph/19_implement_prims_algorithm.cpp new file mode 100644 index 0000000..22d5996 --- /dev/null +++ b/12_graph/19_implement_prims_algorithm.cpp @@ -0,0 +1,217 @@ +/* + link: https://practice.geeksforgeeks.org/problems/minimum-spanning-tree/1# + + sol: https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/ + + video: https://youtu.be/HnD676J56ak?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + video (implementation): https://youtu.be/oNTsS8lGDHw?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + steps: + 1. form 3 array: key, mst, parent + 2. mark source's node in key as 0. + 3. pick node which is not part of mst and has min. value in key + 4. mark it as part of mst + 5. now iterate to their edges and find min. weight as well as it is not part of mst + 6. if such edge found mark its parent node (don't change the mst status) + 7. update the key's value as it will be min. compare to INT_MAX + 8. repeat from 3. +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + brute force + + TC: O( (N-1) * (N + E) ) => O(N^2) + SC: O(N) + O(N) + O(N) => O(N) , for parent, key, mstSet +*/ +#include +using namespace std; + +int main() { + int N, m; + cin >> N >> m; + vector > adj[N]; + + int a, b, wt; + for (int i = 0; i < m; i++) { + cin >> a >> b >> wt; + adj[a].push_back(make_pair(b, wt)); + adj[b].push_back(make_pair(a, wt)); + } + + int parent[N]; + + int key[N]; + + bool mstSet[N]; + + for (int i = 0; i < N; i++) + key[i] = INT_MAX, mstSet[i] = false; + + + key[0] = 0; + parent[0] = -1; + int ansWeight = 0; + for (int count = 0; count < N - 1; count++) + { + + int mini = INT_MAX, u; + + for (int v = 0; v < N; v++) + if (mstSet[v] == false && key[v] < mini) + mini = key[v], u = v; + + // making u the part of mst + mstSet[u] = true; + + // checking all the edges of u + for (auto it : adj[u]) { + int v = it.first; + int weight = it.second; + if (mstSet[v] == false && weight < key[v]) + parent[v] = u, key[v] = weight; + } + } + + + for (int i = 1; i < N; i++) + cout << parent[i] << " - " << i << " \n"; + return 0; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + efficient solution + using priority_queue + + TC: O( (N + E) * logN) => O(N * logN) + SC: O(N) + O(N) + O(N) +*/ + +#include +using namespace std; + +int main() { + int N, m; + cin >> N >> m; + vector > adj[N]; + + int a, b, wt; + for (int i = 0; i < m; i++) { + cin >> a >> b >> wt; + adj[a].push_back(make_pair(b, wt)); + adj[b].push_back(make_pair(a, wt)); + } + + int parent[N]; + + int key[N]; + + bool mstSet[N]; + + for (int i = 0; i < N; i++) + key[i] = INT_MAX, mstSet[i] = false; + + priority_queue< pair, vector >, greater> > pq; + + key[0] = 0; + parent[0] = -1; + pq.push({ 0, 0 }); + // Run the loop till all the nodes have been visited + // because in the brute code we checked for mstSet[node] == false while computing the minimum + // but here we simply take the minimal from the priority queue, so a lot of times a node might be taken twice + // hence its better to keep running till all the nodes have been taken. + // try the following case: + // Credits: Srejan Bera + // 6 7 + // 0 1 5 + // 0 2 10 + // 0 3 100 + // 1 3 50 + // 1 4 200 + // 3 4 250 + // 4 5 50 + while (!pq.empty()) + { + int u = pq.top().second; + pq.pop(); + + mstSet[u] = true; + + for (auto it : adj[u]) { + int v = it.first; + int weight = it.second; + if (mstSet[v] == false && weight < key[v]) { + parent[v] = u; + key[v] = weight; + pq.push({ key[v], v }); + } + } + } + + for (int i = 1; i < N; i++) + cout << parent[i] << " - " << i << " \n"; + return 0; +} + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Accepted +*/ +int spanningTree(int V, vector> adj[]) +{ + int parent[V]; + bool mstSet[V]; + int key[V]; + + for (int i = 0; i < V; i++) { + key[i] = INT_MAX; + mstSet[i] = false; + } + + priority_queue, vector>, greater>> pq; + + key[0] = 0; + parent[0] = -1; + pq.push({ 0, 0 }); + + int ans = 0; + + while (!pq.empty()) { + int u = pq.top().second; + pq.pop(); + + mstSet[u] = true; + + for (vector p : adj[u]) { + int v = p[0]; + int weight = p[1]; + + if (mstSet[v] == false && weight < key[v]) { + key[v] = weight; + parent[v] = u; + pq.push({ weight, v }); + } + } + } + + for (int i = 0;i < V;i++) { + if (key[i] != INT_MAX) ans += key[i]; + } + + return ans; +} \ No newline at end of file diff --git a/12_graph/20_total_no_of_spanning_tree_in_graph.cpp b/12_graph/20_total_no_of_spanning_tree_in_graph.cpp new file mode 100644 index 0000000..b141dad --- /dev/null +++ b/12_graph/20_total_no_of_spanning_tree_in_graph.cpp @@ -0,0 +1,5 @@ +/* + link: https://www.geeksforgeeks.org/total-number-spanning-trees-graph/ + [nice way to find total no. of spanning tree] + [also called Kirchhoff’s Theorem] +*/ diff --git a/12_graph/21_implement_bellman_ford_algorithm.cpp b/12_graph/21_implement_bellman_ford_algorithm.cpp new file mode 100644 index 0000000..8aa1947 --- /dev/null +++ b/12_graph/21_implement_bellman_ford_algorithm.cpp @@ -0,0 +1,116 @@ +/* + link: https://practice.geeksforgeeks.org/problems/negative-weight-cycle3504/1 + + sol: https://www.geeksforgeeks.org/detect-negative-cycle-graph-bellman-ford/ + + video: https://youtu.be/75yC1vbS8S8?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + djikstra's algo doesn't work for the negative edges +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N-1) * O(E) + SC: O(N) +*/ + +#include +using namespace std; +struct node { + int u; + int v; + int wt; + node(int first, int second, int weight) { + u = first; + v = second; + wt = weight; + } +}; + +int main() { + int N, m; + cin >> N >> m; + vector edges; + for (int i = 0;i < m;i++) { + int u, v, wt; + cin >> u >> v >> wt; + edges.push_back(node(u, v, wt)); + } + + int src; + cin >> src; + + + int inf = 10000000; + vector dist(N, inf); + + dist[src] = 0; + + for (int i = 1;i <= N - 1;i++) { + for (auto it : edges) { + if (dist[it.u] + it.wt < dist[it.v]) { + dist[it.v] = dist[it.u] + it.wt; + } + } + } + + // if still reduces means graph is having negative cycle + int fl = 0; + for (auto it : edges) { + if (dist[it.u] + it.wt < dist[it.v]) { + cout << "Negative Cycle"; + fl = 1; + break; + } + } + + // if it doesn't have neg. cycle print the shortest path + if (!fl) { + for (int i = 0;i < N;i++) { + cout << i << " " << dist[i] << endl; + } + } + + return 0; +} + +/* +6 7 +3 2 6 +5 3 1 +0 1 5 +1 5 -3 +1 2 -2 +3 4 -2 +2 4 3 +0 +*/ + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// [accepted] +int isNegativeWeightCycle(int n, vector>edges) { + int inf = 1e7; + vector dist(n, inf); + + for (int i = 0; i < n - 1; i++) { + for (vector j : edges) { + if (dist[j[0]] + j[2] < dist[j[1]]) { + dist[j[1]] = dist[j[0]] + j[2]; + } + } + } + + for (vector j : edges) { + if (dist[j[0]] + j[2] < dist[j[1]]) { + return 1; + } + } + return 0; +} \ No newline at end of file diff --git a/12_graph/22_implement_floyd_warshalls_algorithm.cpp b/12_graph/22_implement_floyd_warshalls_algorithm.cpp new file mode 100644 index 0000000..f0b89d8 --- /dev/null +++ b/12_graph/22_implement_floyd_warshalls_algorithm.cpp @@ -0,0 +1,120 @@ +/* + [shortest path finding algo] + + link: https://practice.geeksforgeeks.org/problems/implementing-floyd-warshall2042/1 + + video: https://youtu.be/nV_wOZnhbog + => floyd warshalls can detect negative edge cycle [6:02] + => including the adjacent node wont help as it will already given in adj. matrix [8:40] + + sol (just refer the comments in code): https://www.geeksforgeeks.org/floyd-warshall-algorithm-dp-16/ + + logic: + if visiting via K then formula will be : d[i][j] = min(d[i][j], d[i][k]+d[k][j]); +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(V^3) + SC: O(V^2) +*/ +#include +using namespace std; + +#define V 6 //No of vertices + +void floyd_warshall(int graph[V][V]) +{ + int dist[V][V]; + + //Assign all values of graph to allPairs_SP + for (int i = 0;i < V;++i) + for (int j = 0;j < V;++j) + dist[i][j] = graph[i][j]; + + //Find all pairs shortest path by trying all possible paths + for (int k = 0;k < V;++k) //Try all intermediate nodes + for (int i = 0;i < V;++i) //Try for all possible starting position + for (int j = 0;j < V;++j) //Try for all possible ending position + { + if (dist[i][k] == INT_MAX || dist[k][j] == INT_MAX) //SKIP if K is unreachable from i or j is unreachable from k + continue; + // dist[i][j] means direct edge from i to j + // dist[i][k] + dist[k][j] means distance via vertex k to reach j from i. + else if (dist[i][k] + dist[k][j] < dist[i][j]) //Check if new distance is shorter via vertex K + dist[i][j] = dist[i][k] + dist[k][j]; + } + + //Check for negative edge weight cycle + for (int i = 0;i < V;++i) + if (dist[i][i] < 0) + { + cout << "Negative edge weight cycle is present\n"; + return; + } + + //Print Shortest Path Graph + //(Values printed as INT_MAX defines there is no path) + for (int i = 1;i < V;++i) + { + for (int j = 0;j < V;++j) + cout << i << " to " << j << " distance is " << dist[i][j] << "\n"; + cout << "=================================\n"; + } +} + +int main() +{ + int graph[V][V] = { {0, 1, 4, INT_MAX, INT_MAX, INT_MAX}, + {INT_MAX, 0, 4, 2, 7, INT_MAX}, + {INT_MAX, INT_MAX, 0, 3, 4, INT_MAX}, + {INT_MAX, INT_MAX, INT_MAX, 0, INT_MAX, 4}, + {INT_MAX, INT_MAX, INT_MAX, 3, 0, INT_MAX}, + {INT_MAX, INT_MAX, INT_MAX, INT_MAX, 5, 0} }; + + floyd_warshall(graph); + return 0; +} + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + [accepted] +*/ +const int INF = 1e8; + +void shortest_distance(vector>& matrix) { + int V = matrix.size(); + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + if (matrix[i][j] == -1) { + matrix[i][j] = INF; + } + } + } + + for (int k = 0; k < V; k++) { + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + if (matrix[i][k] == INF || matrix[k][j] == INF) continue; + matrix[i][j] = min(matrix[i][j], matrix[i][k] + matrix[k][j]); + } + } + } + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + if (matrix[i][j] == INF) { + matrix[i][j] = -1; + } + } + } +} \ No newline at end of file diff --git a/12_graph/23_travelling_salesman_problem.cpp b/12_graph/23_travelling_salesman_problem.cpp new file mode 100644 index 0000000..f64d180 --- /dev/null +++ b/12_graph/23_travelling_salesman_problem.cpp @@ -0,0 +1,89 @@ +/* + TSP: travelling salesman problem + + link (just for ref.): https://www.geeksforgeeks.org/travelling-salesman-problem-set-1/ + [read intro of the statement] [diff between Hamiltonian Cycle and TSP] + + The Hamiltoninan cycle problem is to find if there exist a tour that visits + every city exactly once. Here we know that Hamiltonian Tour exists (because + the graph is complete) and in fact many such tours exist, the problem is to + find a minimum weight Hamiltonian Cycle. + + + problem: + given cities and dist. between each pair of cities, + find the shortest possible path that visits each cities and return to origin city + + optimization using DP + + video: https://youtu.be/JE0JE8ce1V0 + [26:42] for time complexity + + +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + without DP: + TC: O( (n-1)! ) + + with DP: (2^N) as in bitmasking it will go from 0 to (2^N)-1 + TC: O( (2^N) * N ) + SC: O( (2^N) * N ) +*/ +#include +using namespace std; + +#define INT_MAX 999999 + +int n = 4; +int dist[10][10] = { + {0,20,42,25}, + {20,0,30,34}, + {42,30,0,10}, + {25,34,10,0} +}; +int VISITED_ALL = (1 << n) - 1; + +int dp[16][4]; // dp[2^n][n]; + + +int tsp(int mask, int pos) { + + if (mask == VISITED_ALL) { + return dist[pos][0]; + } + if (dp[mask][pos] != -1) { + return dp[mask][pos]; + } + + //Now from current node, we will try to go to every other node and take the min ans + int ans = INT_MAX; + + //Visit all the unvisited cities and take the best route + for (int city = 0;city < n;city++) { + + if ((mask & (1 << city)) == 0) { + + int newAns = dist[pos][city] + tsp(mask | (1 << city), city); + ans = min(ans, newAns); + } + + } + + return dp[mask][pos] = ans; +} + +int main() { + /* init the dp array */ + for (int i = 0;i < (1 << n);i++) { + for (int j = 0;j < n;j++) { + dp[i][j] = -1; + } + } + cout << "Travelling Saleman Distance is " << tsp(1, 0); + + return 0; +} diff --git a/12_graph/24_graph_coloring_problem.cpp b/12_graph/24_graph_coloring_problem.cpp new file mode 100644 index 0000000..735bac4 --- /dev/null +++ b/12_graph/24_graph_coloring_problem.cpp @@ -0,0 +1,112 @@ +/* + link: https://www.geeksforgeeks.org/graph-coloring-applications/#:~:text=Graph%20coloring%20problem%20is%20to,are%20colored%20using%20same%20color. + + link2: https://www.geeksforgeeks.org/graph-coloring-set-2-greedy-algorithm/ + +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +// A C++ program to implement greedy algorithm for graph coloring +#include +#include +using namespace std; + +// A class that represents an undirected graph +class Graph +{ + int V; // No. of vertices + list* adj; // A dynamic array of adjacency lists +public: + // Constructor and destructor + Graph(int V) { this->V = V; adj = new list[V]; } + ~Graph() { delete[] adj; } + + // function to add an edge to graph + void addEdge(int v, int w); + + // Prints greedy coloring of the vertices + void greedyColoring(); +}; + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); + adj[w].push_back(v); // Note: the graph is undirected +} + +// Assigns colors (starting from 0) to all vertices and prints +// the assignment of colors +void Graph::greedyColoring() +{ + int result[V]; + + // Assign the first color to first vertex + result[0] = 0; + + // Initialize remaining V-1 vertices as unassigned + for (int u = 1; u < V; u++) + result[u] = -1; // no color is assigned to u + + // A temporary array to store the available colors. True + // value of available[cr] would mean that the color cr is + // assigned to one of its adjacent vertices + bool available[V]; + for (int cr = 0; cr < V; cr++) + available[cr] = false; + + // Assign colors to remaining V-1 vertices + for (int u = 1; u < V; u++) + { + // Process all adjacent vertices and flag their colors + // as unavailable + list::iterator i; + for (i = adj[u].begin(); i != adj[u].end(); ++i) + if (result[*i] != -1) + available[result[*i]] = true; + + // Find the first available color + int cr; + for (cr = 0; cr < V; cr++) + if (available[cr] == false) + break; + + result[u] = cr; // Assign the found color + + // Reset the values back to false for the next iteration + for (i = adj[u].begin(); i != adj[u].end(); ++i) + if (result[*i] != -1) + available[result[*i]] = false; + } + + // print the result + for (int u = 0; u < V; u++) + cout << "Vertex " << u << " ---> Color " + << result[u] << endl; +} + +// Driver program to test above function +int main() +{ + Graph g1(5); + g1.addEdge(0, 1); + g1.addEdge(0, 2); + g1.addEdge(1, 2); + g1.addEdge(1, 3); + g1.addEdge(2, 3); + g1.addEdge(3, 4); + cout << "Coloring of graph 1 \n"; + g1.greedyColoring(); + + Graph g2(5); + g2.addEdge(0, 1); + g2.addEdge(0, 2); + g2.addEdge(1, 2); + g2.addEdge(1, 4); + g2.addEdge(2, 4); + g2.addEdge(4, 3); + cout << "\nColoring of graph 2 \n"; + g2.greedyColoring(); + + return 0; +} diff --git a/12_graph/25_snake_and_ladders_problem.cpp b/12_graph/25_snake_and_ladders_problem.cpp new file mode 100644 index 0000000..0352705 --- /dev/null +++ b/12_graph/25_snake_and_ladders_problem.cpp @@ -0,0 +1,75 @@ +/* + link: https://leetcode.com/problems/snakes-and-ladders/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS + + logic: everytime steps will be increase in BFS style, like (successor's step = predecessor's step + 1); + so all reachable block from predecessor's step will be marked **predecessor's step + 1**; +*/ +class Solution { +public: + int snakesAndLadders(vector>& board) { + int N = board.size(); + + // target to reach + int target = N * N; + + // to track visited blocks + vector vis(N * N + 1, 0); + + // pair : current pos, steps + queue> q; + + // starting with 1 (in board (n-1,0)) + q.push({ 1, 0 }); + + while (!q.empty()) { + auto curr = q.front(); + q.pop(); + + // target found + if (curr.first == target) return curr.second; + + // out of range + if (curr.first > target) continue; + + // already visited + if (vis[curr.first]) continue; + + // mark visited + vis[curr.first] = 1; + + // checking all board with possibility of dice + for (int i = 1;i <= 6;i++) { + // out of board + if (curr.first + i > target) break; + + // every dice move + int newNum = curr.first + i; + + // r: curr row from bottom side (Boustrophedon style) + int r = (newNum - 1) / N, col; + + // row acc. to the board + int row = N - 1 - r; + + // if r is even then col will be from left to right + if (r % 2 == 0) col = (newNum - 1) % N; + // if r is odd then col will be from right to left + else col = N - 1 - (newNum - 1) % N; + + // push the new BFS based block + // how BFS? : (see curr.second + 1) + q.push({ board[row][col] == -1 ? newNum : board[row][col], curr.second + 1 }); + } + } + + // target is unreachable + return -1; + } +}; \ No newline at end of file diff --git a/12_graph/26_find_bridge_in_graph_(cut_edge).cpp b/12_graph/26_find_bridge_in_graph_(cut_edge).cpp new file mode 100644 index 0000000..55d23f6 --- /dev/null +++ b/12_graph/26_find_bridge_in_graph_(cut_edge).cpp @@ -0,0 +1,69 @@ +/* + sol: https://www.geeksforgeeks.org/bridge-in-a-graph/ + + An edge in an undirected connected graph is a bridge iff removing it disconnects the graph. + For a disconnected undirected graph, definition is similar, a bridge is an edge removing + which increases number of disconnected components. + Like Articulation Points, bridges represent vulnerabilities in a connected network and + are useful for designing reliable networks. For example, in a wired computer network, an + articulation point indicates the critical computers and a bridge indicates the critical + wires or connections. + + video: https://youtu.be/2rjZH0-2lhk?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N + E) + SC: O(N) + O(N) +*/ +#include +using namespace std; +void dfs(int node, int parent, vector& vis, vector& tin, vector& low, int& timer, vector adj[]) { + vis[node] = 1; + tin[node] = low[node] = timer++; + for (auto it : adj[node]) { + if (it == parent) continue; + + if (!vis[it]) { + dfs(it, node, vis, tin, low, timer, adj); + low[node] = min(low[node], low[it]); + + // low [it] > tin[node] means adjacent's low is so higher than current's tin means + // to reach adjacent node it's through only current node. + // hence it's bridge + if (low[it] > tin[node]) { + cout << node << " " << it << endl; + } + } + // node is visited and is not parent then update the low of current node to tin of adjacent + else { + low[node] = min(low[node], tin[it]); + } + } +} +int main() { + int n, m; + cin >> n >> m; + vector adj[n]; + for (int i = 0;i < m;i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + + vector tin(n, -1); + vector low(n, -1); + vector vis(n, 0); + int timer = 0; + for (int i = 0;i < n;i++) { + if (!vis[i]) { + dfs(i, -1, vis, tin, low, timer, adj); + } + } + + return 0; +} \ No newline at end of file diff --git a/12_graph/27_kosaraju_algo_count_strongly_connected_components.cpp b/12_graph/27_kosaraju_algo_count_strongly_connected_components.cpp new file mode 100644 index 0000000..752116c --- /dev/null +++ b/12_graph/27_kosaraju_algo_count_strongly_connected_components.cpp @@ -0,0 +1,149 @@ +/* + link: https://practice.geeksforgeeks.org/problems/strongly-connected-components-kosarajus-algo/1# + + sol (just refer): https://www.geeksforgeeks.org/strongly-connected-components/ + + video: https://youtu.be/V8qIqJxCioo?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(V) + O(V + E) + O(V + E), 1st for toposort, 2nd for transpose, 3rd for DFS acc. to finishing line + SC: O(V + E) + O(V) + O(V), 1st for storing transpose, 2nd for vis, 3rd for stack +*/ +#include +using namespace std; +void dfs(int node, stack& st, vector& vis, vector adj[]) { + vis[node] = 1; + for (auto it : adj[node]) { + if (!vis[it]) { + dfs(it, st, vis, adj); + } + } + + st.push(node); +} + +void revDfs(int node, vector& vis, vector transpose[]) { + cout << node << " "; + vis[node] = 1; + for (auto it : transpose[node]) { + if (!vis[it]) { + revDfs(it, vis, transpose); + } + } +} + +int main() { + int n, m; + cin >> n >> m; + vector adj[n]; + for (int i = 0;i < m;i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + } + + stack st; + vector vis(n, 0); + for (int i = 0;i < n;i++) { + if (!vis[i]) { + dfs(i, st, vis, adj); + } + } + + vector transpose[n]; + + for (int i = 0;i < n;i++) { + vis[i] = 0; + for (auto it : adj[i]) { + transpose[it].push_back(i); + } + } + + + + while (!st.empty()) { + int node = st.top(); + st.pop(); + if (!vis[node]) { + cout << "SCC: "; + revDfs(node, vis, transpose); + cout << endl; + } + } + + + return 0; +} + +/* +5 5 +0 1 +1 2 +2 0 +1 3 +3 4 +*/ + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + [accepted] +*/ +void dfs(int curr, stack& st, vector& vis, vector adj[]) { + vis[curr] = 1; + for (auto i : adj[curr]) { + if (!vis[i]) dfs(i, st, vis, adj); + } + st.push(curr); +} + +void revDfs(int curr, vector& vis, vector transpose[]) { + vis[curr] = 1; + for (auto it : transpose[curr]) { + if (!vis[it]) revDfs(it, vis, transpose); + } +} + + +int kosaraju(int V, vector adj[]) +{ + stack st; + vector vis(V, 0); + for (int i = 0; i < V; i++) { + if (!vis[i]) { + dfs(i, st, vis, adj); + } + } + + vector transpose[V]; + + for (int i = 0; i < V; i++) { + vis[i] = 0; + for (auto it : adj[i]) { + transpose[it].push_back(i); + } + } + + int cnt = 0; + + while (!st.empty()) { + int node = st.top(); + st.pop(); + if (!vis[node]) { + cnt++; + revDfs(node, vis, transpose); + } + } + + return cnt; +} \ No newline at end of file diff --git a/12_graph/28_check_if_graph_is_bipartite_or_not.cpp b/12_graph/28_check_if_graph_is_bipartite_or_not.cpp new file mode 100644 index 0000000..4880f32 --- /dev/null +++ b/12_graph/28_check_if_graph_is_bipartite_or_not.cpp @@ -0,0 +1,91 @@ +/* + link: https://practice.geeksforgeeks.org/problems/bipartite-graph/1 + + sol: https://www.geeksforgeeks.org/bipartite-graph/ + + video (BFS): https://youtu.be/nbgaEu-pvkU?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + video (DFS): https://youtu.be/uC884ske2uQ?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + graph which can be colored using 2 color and no two adjacent should have same color + + case 1: with no cycle then definetly it is bipartite + case 2: with even cycle length it is also bipartite + case 3: with odd cycle length then it is not bipartite +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + BFS + TC: O(V + E) + SC: O(V + E) +*/ +bool bfs(int src, vector& color, vector adj[]) { + color[src] = 0; + + queue q; + q.push(src); + + while (!q.empty()) { + int curr = q.front(); + q.pop(); + + for (int i : adj[curr]) { + if (color[i] == -1) { + color[i] = 1 - color[curr]; + q.push(i); + } + else if (color[i] == color[curr]) return false; + } + } + return true; +} + +bool isBipartite(int V, vectoradj[]) { + vector color(V, -1); + + for (int i = 0;i < V;i++) { + if (color[i] == -1) { + if (!bfs(i, color, adj)) return false; + } + } + return true; +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + DFS + TC: O(V + E) + SC: O(V + E) +*/ +bool dfs(int curr, int parent, vector& color, vector adj[]) { + color[curr] = 1 - color[parent]; + + for (int i : adj[curr]) { + if (color[i] == -1) { + color[i] = 1 - color[curr]; + if (!dfs(i, curr, color, adj)) return false; + } + // color is same as well as it is not parent + else if (color[i] == color[curr] && i != parent) return false; + } + + return true; +} + +bool isBipartite(int V, vectoradj[]) { + vector color(V, -1); + + for (int i = 0;i < V;i++) { + if (color[i] == -1) { + if (!dfs(i, -1, color, adj)) return false; + } + } + return true; +} \ No newline at end of file diff --git a/12_graph/29_detect_negative_cycle_in_graph.cpp b/12_graph/29_detect_negative_cycle_in_graph.cpp new file mode 100644 index 0000000..a9b84d2 --- /dev/null +++ b/12_graph/29_detect_negative_cycle_in_graph.cpp @@ -0,0 +1,5 @@ +/* + sol: https://www.geeksforgeeks.org/detect-negative-cycle-graph-bellman-ford/ + + ref: 21_implement_bellman_ford_algorithm +*/ \ No newline at end of file diff --git a/12_graph/30_longest_path_in_directed_acyclic_graph.cpp b/12_graph/30_longest_path_in_directed_acyclic_graph.cpp new file mode 100644 index 0000000..db6210c --- /dev/null +++ b/12_graph/30_longest_path_in_directed_acyclic_graph.cpp @@ -0,0 +1,75 @@ +/* + link: https://www.geeksforgeeks.org/find-longest-path-directed-acyclic-graph/ + logic: read intro in link + + video: https://youtu.be/jdTnoCBSOVM +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +#include +#define int long long int +#define pb push_back +#define ps(x,y) fixed<>x; while(x--) +using namespace std; + + +vector order; + +void topo(int src, vector& vis, vector > > g) { + vis[src] = 1; + for (auto x : g[src]) { + if (!vis[x.first]) + topo(x.first, vis, g); + } + order.push_back(src); +} + + +int32_t main() { + + int v, e; + cin >> v >> e; + + int src; + cin >> src; + + vector > > g(v); + for (int i = 0;i < e;i++) { + int x, y, w; + cin >> x >> y >> w; + g[x].push_back({ y,w }); + } + + vector vis(v, 0); + for (int i = 0;i < v;i++) { + if (!vis[i]) { + topo(i, vis, g); + } + } + vector dist(v); + for (int i = 0;i < v;i++) dist[i] = INT_MIN; + dist[src] = 0; + for (int i = v - 1;i >= 0;i--) { + if (dist[order[i]] != INT_MIN) { + for (auto x : g[order[i]]) { + int v = dist[x.first]; + int w = x.second; + int u = dist[order[i]]; + if (u + w > v) + dist[x.first] = u + w; + } + } + } + for (int i = 0;i < v;i++) { + if (i != src and dist[i] != INT_MIN) { + cout << src << " -> " << i << " = " << dist[i] << endl; + } + } + + return 0; + +} diff --git a/12_graph/31_journey_to_the_moon.cpp b/12_graph/31_journey_to_the_moon.cpp new file mode 100644 index 0000000..701a14f --- /dev/null +++ b/12_graph/31_journey_to_the_moon.cpp @@ -0,0 +1,81 @@ +/* + link: https://www.hackerrank.com/challenges/journey-to-the-moon/problem + + video: https://youtu.be/IM1xOjamHA8 +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using dfs + TC: O(V+E) + SC: O() +*/ +#include +#define int long long int +#define pb push_back +#define ps(x,y) fixed<>x; while(x--) +using namespace std; + +void dfile() { +#ifndef ONLINE_JUDGE + freopen("input.txt", "r", stdin); + freopen("output.txt", "w", stdout); +#endif + ios_base::sync_with_stdio(false); + cin.tie(NULL); +} + +void dfs(int src, vector& vis, vector g[], int& counter) { + vis[src] = 1; + counter++; + for (auto x : g[src]) { + if (!vis[x]) { + dfs(x, vis, g, counter); + } + } +} + +int32_t main() +{ + + int v, e; + cin >> v >> e; + vector g[v]; + for (int i = 0;i < e;i++) { + int x, y; + cin >> x >> y; + g[x].push_back(y); + g[y].push_back(x); + } + vector solution; + vector vis(v, 0); + for (int i = 0;i < v;i++) { + if (!vis[i]) { + // count of astronauts in each country + int counter = 0; + dfs(i, vis, g, counter); + solution.push_back(counter); + } + } + + /* + whenever used (x * x-1) /2 + it means xC2 => as we r choosing 2 out of x + */ + + // total no. of pairs + int val = (v * (v - 1)) / 2; + for (int i = 0;i < solution.size();i++) { + // no. pairs in individual country + int x = (solution[i] * (solution[i] - 1)) / 2; + + // as we want astronauts from different country + val = val - x; + } + cout << val; + + return 0; +} diff --git a/12_graph/32_cheapest_flights_within_K_stops.cpp b/12_graph/32_cheapest_flights_within_K_stops.cpp new file mode 100644 index 0000000..7296a10 --- /dev/null +++ b/12_graph/32_cheapest_flights_within_K_stops.cpp @@ -0,0 +1,172 @@ +/* + link: https://leetcode.com/problems/cheapest-flights-within-k-stops/description/ + + hint: use shortest path algo +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + DFS +*/ +void dfs(int s, int d, int k, int cost, vector& visited, int& ans, unordered_map>>& g) { + if (s == d) { ans = cost; return; } + if (k == 0) return; + visited[s] = 1; + for (const auto& x : g[s]) { + if (visited[x.first] == 0) { + if (cost + x.second > ans) continue; // IMPORTANT!!! prunning + + dfs(x.first, d, k - 1, cost + x.second, visited, ans, g); + + } + } + visited[s] = 0; +} +int findCheapestPrice(int n, vector>& flights, int s, int d, int K) { + unordered_map>> g; + for (const auto& e : flights) + g[e[0]].emplace_back(e[1], e[2]); + int ans = INT_MAX; + vector visited(n, 0); + dfs(s, d, K + 1, 0, visited, ans, g); + return ans == INT_MAX ? -1 : ans; +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS +*/ +int findCheapestPrice(int n, vector>& flights, int s, int d, int K) { + unordered_map>> g; + for (const auto& e : flights) + g[e[0]].emplace_back(e[1], e[2]); + int ans = INT_MAX; + queue> q; + q.push({ s,0 }); + int steps = 0; + while (!q.empty()) { + int n = q.size(); + for (int i = 0; i < n; ++i) { + auto curr = q.front();q.pop(); + if (curr.first == d) ans = min(ans, curr.second); + for (auto x : g[curr.first]) { + if (curr.second + x.second > ans) continue; + q.push({ x.first,curr.second + x.second }); + } + } + if (steps++ > K) break; + } + + return ans == INT_MAX ? -1 : ans; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using bellman ford +*/ +class Solution { +public: + //bellman ford. + //just run it k+1 iterations. + int findCheapestPrice(int n, vector>& a, int src, int sink, int k) { + + vector c(n, 1e8); + c[src] = 0; + + for (int z = 0; z <= k; z++) { + vector C(c); + for (auto e : a) + C[e[1]] = min(C[e[1]], c[e[0]] + e[2]); + c = C; + } + return c[sink] == 1e8 ? -1 : c[sink]; + } +}; + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using priority_queue, BFS +*/ +class node { +public: + int u; + int v; + int stop; + node(int u1, int v1, int k) + { + u = u1; + v = v1; + stop = k; + } +}; + +class Solution { +public: + + struct compare { + bool operator()(node& n1, node& n2) + { + return n1.v > n2.v; + } + }; + int findCheapestPrice(int n, vector>& flights, int src, int dst, int k) { + + vector> graph[n]; + + for (int i = 0;i < flights.size();i++) + { + int u = flights[i][0]; + int v = flights[i][1]; + int w = flights[i][2]; + graph[u].push_back(make_pair(v, w)); + } + + int dist[n]; + + for (int i = 0;i < n;i++) dist[i] = INT_MAX; + + dist[src] = 0; + + priority_queue, compare> pq; + + pq.push(node(src, 0, 0)); + + while (!pq.empty()) + { + node n1 = pq.top(); + pq.pop(); + + if (n1.u == dst) return n1.v; + + + if (n1.stop > k) continue; + + if (dist[n1.u] != INT_MAX && dist[n1.u] < n1.stop) continue; + + dist[n1.u] = n1.stop; + + for (int i = 0;i < graph[n1.u].size();i++) + { + pq.push(node(graph[n1.u][i].first, n1.v + graph[n1.u][i].second, n1.stop + 1)); + } + } + return -1; + } +}; \ No newline at end of file diff --git a/12_graph/33_oliver_and_the_game.cpp b/12_graph/33_oliver_and_the_game.cpp new file mode 100644 index 0000000..fa91147 --- /dev/null +++ b/12_graph/33_oliver_and_the_game.cpp @@ -0,0 +1,98 @@ +/* + link: https://www.hackerearth.com/practice/algorithms/graphs/topological-sort/practice-problems/algorithm/oliver-and-the-game-3/ + + video: https://youtu.be/5h1JYjin_4o + + euler tour: https://www.geeksforgeeks.org/euler-tour-tree/ + + here in this problem we can do just 2 things either go towards the mantion or away from the mantion + not both. +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +#include +#define int long long int +#define pb push_back +#define ps(x,y) fixed<>x; while(x--) +using namespace std; + + +vector inTime; +vector outTime; +int timer = 1; + +void resize(int n) { + inTime.resize(n + 1); + outTime.resize(n + 1); +} + +void dfs(int src, int par, vector g[]) { + inTime[src] = timer++; + for (auto x : g[src]) { + if (x != par) { + dfs(x, src, g); + } + } + outTime[src] = timer++; +} + +// is x in sub-tree of y +bool check(int x, int y) { + if (inTime[x] > inTime[y] and outTime[x] < outTime[y]) + return true; + return false; +} + + +int32_t main() { + ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); + int n; + cin >> n; + timer = 1; + resize(n); + vector g[n + 1]; + for (int i = 0;i < n - 1;i++) { + int x, y; + cin >> x >> y; + g[x].push_back(y); + g[y].push_back(x); + } + dfs(1, 0, g); + int q; + cin >> q; + for (int i = 0;i < q;i++) { + int type, x, y; + cin >> type >> x >> y; + if (!check(x, y) and !check(y, x)) { + cout << "NO\n"; + continue; + } + if (type == 0) { + /* + means we have to go towards the mantion + hence check if y is in sub-tree of x. (as it is) + */ + if (check(y, x)) + cout << "YES\n"; + else + cout << "NO\n"; + } + else if (type == 1) { + /* + means we have to go away from the mantion + hence check if x is in sub-tree of y. (just swap the x and y to reuse the func.) + */ + if (check(x, y)) + cout << "YES\n"; + else + cout << "NO\n"; + } + + } + + return 0; +} diff --git a/12_graph/34_waterJug_problem_using_BFS.cpp b/12_graph/34_waterJug_problem_using_BFS.cpp new file mode 100644 index 0000000..61c99cc --- /dev/null +++ b/12_graph/34_waterJug_problem_using_BFS.cpp @@ -0,0 +1,149 @@ +/* + link: https://www.geeksforgeeks.org/water-jug-problem-using-bfs/ +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +#include +using namespace std; +typedef pair pii; +void printpath(mapmp, pii u) +{ + if (u.first == 0 && u.second == 0) + { + cout << 0 << " " << 0 << endl; + return; + } + printpath(mp, mp[u]); + cout << u.first << " " << u.second << endl; +} +void BFS(int a, int b, int target) +{ + mapm; + bool isSolvable = false; + vector>path; + mapmp; + + queueq; + + q.push(make_pair(0, 0)); + while (!q.empty()) + { + auto u = q.front(); + q.pop(); + + // already visited + if (m[u] == 1) continue; + + // out of capacity + if ((u.first > a || u.second > b || u.first < 0 || u.second < 0)) continue; + + // mark visited + m[{u.first, u.second}] = 1; + + // either of the jug reached target + if (u.first == target || u.second == target) + { + isSolvable = true; + + printpath(mp, u); + if (u.first == target) { + if (u.second != 0) + cout << u.first << " " << 0 << endl; + } + else { + if (u.first != 0) + cout << 0 << " " << u.second << endl; + } + return; + } + + // completely fill the jug 2 + if (m[{u.first, b}] != 1) + { + q.push({ u.first,b }); + mp[{u.first, b}] = u; + } + + // completely fill the jug 1 + if (m[{a, u.second}] != 1) + { + q.push({ a,u.second }); + mp[{a, u.second}] = u; + } + + //transfer jug 1 -> jug 2 + // d: how much more water can be poured + int d = b - u.second; + // first jug is having enough + if (u.first >= d) + { + int c = u.first - d; + if (m[{c, b}] != 1) + { + q.push({ c,b }); + mp[{c, b}] = u; + } + } + // first jug is having not enough to fill whole jug 2 + else + { + int c = u.first + u.second; + if (m[{0, c}] != 1) + { + q.push({ 0,c }); + mp[{0, c}] = u; + } + } + + + //transfer jug 2 -> jug 1 + d = a - u.first; + if (u.second >= d) + { + int c = u.second - d; + if (m[{a, c}] != 1) + { + q.push({ a,c }); + mp[{a, c}] = u; + } + } + else + { + int c = u.first + u.second; + if (m[{c, 0}] != 1) + { + q.push({ c,0 }); + mp[{c, 0}] = u; + } + } + + // empty the jug 2 + if (m[{u.first, 0}] != 1) + { + q.push({ u.first,0 }); + mp[{u.first, 0}] = u; + } + + // empty the jug 1 + if (m[{0, u.second}] != 1) + { + q.push({ 0,u.second }); + mp[{0, u.second}] = u; + } + + + } + if (!isSolvable) + cout << "No solution"; +} + + +int main() +{ + int Jug1 = 5, Jug2 = 7, target = 3; + cout << "Path from initial state " + "to solution state ::\n"; + BFS(Jug1, Jug2, target); + return 0; +} diff --git a/12_graph/36_Find_if_there_is_a_path_of_more_than_k_length_from_a_source.cpp b/12_graph/36_Find_if_there_is_a_path_of_more_than_k_length_from_a_source.cpp new file mode 100644 index 0000000..cae3564 --- /dev/null +++ b/12_graph/36_Find_if_there_is_a_path_of_more_than_k_length_from_a_source.cpp @@ -0,0 +1,141 @@ +/* + link: https://www.geeksforgeeks.org/find-if-there-is-a-path-of-more-than-k-length-from-a-source/ + + note: read the logic from link +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Time Complexity: O(n!) +*/ +// Program to find if there is a simple path with +// weight more than k +#include +using namespace std; + +// iPair ==> Integer Pair +typedef pair iPair; + +// This class represents a dipathted graph using +// adjacency list representation +class Graph +{ + int V; // No. of vertices + + // In a weighted graph, we need to store vertex + // and weight pair for every edge + list< pair >* adj; + bool pathMoreThanKUtil(int src, int k, vector& path); + +public: + Graph(int V); // Constructor + + // function to add an edge to graph + void addEdge(int u, int v, int w); + bool pathMoreThanK(int src, int k); +}; + +// Returns true if graph has path more than k length +bool Graph::pathMoreThanK(int src, int k) +{ + // Create a path array with nothing included + // in path + vector path(V, false); + + // Add source vertex to path + path[src] = 1; + + return pathMoreThanKUtil(src, k, path); +} + +// Prints shortest paths from src to all other vertices +bool Graph::pathMoreThanKUtil(int src, int k, vector& path) +{ + // If k is 0 or negative, return true; + if (k <= 0) + return true; + + // Get all adjacent vertices of source vertex src and + // recursively explore all paths from src. + list::iterator i; + for (i = adj[src].begin(); i != adj[src].end(); ++i) + { + // Get adjacent vertex and weight of edge + int v = (*i).first; + int w = (*i).second; + + // If vertex v is already there in path, then + // there is a cycle (we ignore this edge) + if (path[v] == true) + continue; + + // If weight of is more than k, return true + if (w >= k) + return true; + + // Else add this vertex to path + path[v] = true; + + // If this adjacent can provide a path longer + // than k, return true. + if (pathMoreThanKUtil(v, k - w, path)) + return true; + + // Backtrack + path[v] = false; + } + + // If no adjacent could produce longer path, return + // false + return false; +} + +// Allocates memory for adjacency list +Graph::Graph(int V) +{ + this->V = V; + adj = new list[V]; +} + +// Utility function to an edge (u, v) of weight w +void Graph::addEdge(int u, int v, int w) +{ + adj[u].push_back(make_pair(v, w)); + adj[v].push_back(make_pair(u, w)); +} + +// Driver program to test methods of graph class +int main() +{ + // create the graph given in above fugure + int V = 9; + Graph g(V); + + // making above shown graph + g.addEdge(0, 1, 4); + g.addEdge(0, 7, 8); + g.addEdge(1, 2, 8); + g.addEdge(1, 7, 11); + g.addEdge(2, 3, 7); + g.addEdge(2, 8, 2); + g.addEdge(2, 5, 4); + g.addEdge(3, 4, 9); + g.addEdge(3, 5, 14); + g.addEdge(4, 5, 10); + g.addEdge(5, 6, 2); + g.addEdge(6, 7, 1); + g.addEdge(6, 8, 6); + g.addEdge(7, 8, 7); + + int src = 0; + int k = 62; + g.pathMoreThanK(src, k) ? cout << "Yes\n" : + cout << "No\n"; + + k = 60; + g.pathMoreThanK(src, k) ? cout << "Yes\n" : + cout << "No\n"; + + return 0; +} diff --git a/12_graph/37_M_coloring_problem.cpp b/12_graph/37_M_coloring_problem.cpp new file mode 100644 index 0000000..0b04168 --- /dev/null +++ b/12_graph/37_M_coloring_problem.cpp @@ -0,0 +1,207 @@ +/* + link: https://practice.geeksforgeeks.org/problems/m-coloring-problem-1587115620/1 + + video: https://youtu.be/h9M0pQ39ha0 +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + BFS +*/ +#include +#define int long long int +#define pb push_back +#define ps(x,y) fixed<>x; while(x--) +using namespace std; + + +void solve() { + + int v, e; + cin >> v >> e; + vector > g(v); + for (int i = 0;i < e;i++) { + int x, y; + cin >> x >> y; + g[x].pb(y); + g[y].pb(x); + } + int res[v]; + bool available[v]; + res[0] = 0; + for (int i = 1;i < v;i++) res[i] = -1; + for (int i = 0;i < v;i++) available[i] = false; + + int cn = 0; + for (int i = 1;i < v;i++) { + for (auto x : g[i]) { + if (res[x] != -1) { + available[res[x]] = true; + } + } + + int cr; + for (cr = 0;cr < v;cr++) { + if (available[cr] == false) { + break; + } + } + + res[i] = cr; + cn = max(cn, cr + 1); + + for (auto x : g[i]) { + if (res[x] != -1) { + available[res[x]] = false; + } + } + } + cout << cn << endl; + for (int i = 0;i < v;i++) cout << res[i] << " "; + +} + +int32_t main() { + + solve(); + return 0; + +} + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + alternative code + + using BFS + + Time Complexity: O(V + E). + Space Complexity: O(V). For Storing Visited List. +*/ +// CPP program for the above approach +#include +#include +using namespace std; + +class node +{ + + // A node class which stores the color and the edges + // connected to the node +public: + int color = 1; + set edges; +}; + +int canPaint(vector& nodes, int n, int m) +{ + + // Create a visited array of n + // nodes, initialized to zero + vector visited(n + 1, 0); + + // maxColors used till now are 1 as + // all nodes are painted color 1 + int maxColors = 1; + + // Do a full BFS traversal from + // all unvisited starting points + for (int sv = 1; sv <= n; sv++) + { + + if (visited[sv]) + continue; + + // If the starting point is unvisited, + // mark it visited and push it in queue + visited[sv] = 1; + queue q; + q.push(sv); + + // BFS Travel starts here + while (!q.empty()) + { + + int top = q.front(); + q.pop(); + + // Checking all adjacent nodes + // to "top" edge in our queue + for (auto it = nodes[top].edges.begin(); + it != nodes[top].edges.end(); it++) + { + + // IMPORTANT: If the color of the + // adjacent node is same, increase it by 1 + if (nodes[top].color == nodes[*it].color) + nodes[*it].color += 1; + + // If number of colors used shoots m, return + // 0 + maxColors + = max(maxColors, max(nodes[top].color, + nodes[*it].color)); + if (maxColors > m) + return 0; + + // If the adjacent node is not visited, + // mark it visited and push it in queue + if (!visited[*it]) { + visited[*it] = 1; + q.push(*it); + } + } + } + } + + return 1; +} + +// Driver code +int main() +{ + + int n = 4; + bool graph[n][n] = { + { 0, 1, 1, 1 }, + { 1, 0, 1, 0 }, + { 1, 1, 0, 1 }, + { 1, 0, 1, 0 } }; + int m = 3; // Number of colors + + + // Create a vector of n+1 + // nodes of type "node" + // The zeroth position is just + // dummy (1 to n to be used) + vector nodes(n + 1); + + // Add edges to each node as per given input + for (int i = 0; i < n; i++) + { + for (int j = 0;j < n;j++) + { + if (graph[i][j]) + { + // Connect the undirected graph + nodes[i].edges.insert(i); + nodes[j].edges.insert(j); + } + } + } + + // Display final answer + cout << canPaint(nodes, n, m); + cout << "\n"; + + return 0; +} diff --git a/12_graph/38_Minimum_edges_to_reverse_to_make_path_from_a_source_to_a_destination.cpp b/12_graph/38_Minimum_edges_to_reverse_to_make_path_from_a_source_to_a_destination.cpp new file mode 100644 index 0000000..7cbe4a6 --- /dev/null +++ b/12_graph/38_Minimum_edges_to_reverse_to_make_path_from_a_source_to_a_destination.cpp @@ -0,0 +1,162 @@ +/* + link: https://www.geeksforgeeks.org/minimum-edges-reverse-make-path-source-destination/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// C++ Program to find minimum edge reversal to get +// atleast one path from source to destination +#include +using namespace std; +# define INF 0x3f3f3f3f + +// This class represents a directed graph using +// adjacency list representation +class Graph +{ + int V; // No. of vertices + + // In a weighted graph, we need to store vertex + // and weight pair for every edge + list< pair >* adj; + +public: + Graph(int V); // Constructor + + // function to add an edge to graph + void addEdge(int u, int v, int w); + + // returns shortest path from s + vector shortestPath(int s); +}; + +// Allocates memory for adjacency list +Graph::Graph(int V) +{ + this->V = V; + adj = new list< pair >[V]; +} + +// method adds a directed edge from u to v with weight w +void Graph::addEdge(int u, int v, int w) +{ + adj[u].push_back(make_pair(v, w)); +} + +// Prints shortest paths from src to all other vertices +vector Graph::shortestPath(int src) +{ + // Create a set to store vertices that are being + // prerocessed + set< pair > setds; + + // Create a vector for distances and initialize all + // distances as infinite (INF) + vector dist(V, INF); + + // Insert source itself in Set and initialize its + // distance as 0. + setds.insert(make_pair(0, src)); + dist[src] = 0; + + /* Looping till all shortest distance are finalized + then setds will become empty */ + while (!setds.empty()) + { + // The first vertex in Set is the minimum distance + // vertex, extract it from set. + pair tmp = *(setds.begin()); + setds.erase(setds.begin()); + + // vertex label is stored in second of pair (it + // has to be done this way to keep the vertices + // sorted distance (distance must be first item + // in pair) + int u = tmp.second; + + // 'i' is used to get all adjacent vertices of a vertex + list< pair >::iterator i; + for (i = adj[u].begin(); i != adj[u].end(); ++i) + { + // Get vertex label and weight of current adjacent + // of u. + int v = (*i).first; + int weight = (*i).second; + + // If there is shorter path to v through u. + if (dist[v] > dist[u] + weight) + { + /* If distance of v is not INF then it must be in + our set, so removing it and inserting again + with updated less distance. + Note : We extract only those vertices from Set + for which distance is finalized. So for them, + we would never reach here. */ + if (dist[v] != INF) + setds.erase(setds.find(make_pair(dist[v], v))); + + // Updating distance of v + dist[v] = dist[u] + weight; + setds.insert(make_pair(dist[v], v)); + } + } + } + return dist; +} + +/* method adds reverse edge of each original edge +in the graph. It gives reverse edge a weight = 1 +and all original edges a weight of 0. Now, the +length of the shortest path will give us the answer. +If shortest path is p: it means we used p reverse +edges in the shortest path. */ +Graph modelGraphWithEdgeWeight(int edge[][2], int E, int V) +{ + Graph g(V); + for (int i = 0; i < E; i++) + { + // original edge : weight 0 + g.addEdge(edge[i][0], edge[i][1], 0); + + // reverse edge : weight 1 + g.addEdge(edge[i][1], edge[i][0], 1); + } + return g; +} + +// Method returns minimum number of edges to be +// reversed to reach from src to dest +int getMinEdgeReversal(int edge[][2], int E, int V, + int src, int dest) +{ + // get modified graph with edge weight + Graph g = modelGraphWithEdgeWeight(edge, E, V); + + // get shortes path vector + vector dist = g.shortestPath(src); + + // If distance of destination is still INF, + // not possible + if (dist[dest] == INF) + return -1; + else + return dist[dest]; +} + +// Driver code to test above method +int main() +{ + int V = 7; + int edge[][2] = { {0, 1}, {2, 1}, {2, 3}, {5, 1}, + {4, 5}, {6, 4}, {6, 3} }; + int E = sizeof(edge) / sizeof(edge[0]); + + int minEdgeToReverse = + getMinEdgeReversal(edge, E, V, 0, 6); + if (minEdgeToReverse != -1) + cout << minEdgeToReverse << endl; + else + cout << "Not possible" << endl; + return 0; +} diff --git a/12_graph/39_paths_to_travel_each_node_using_each_edge_seven_bridge.cpp b/12_graph/39_paths_to_travel_each_node_using_each_edge_seven_bridge.cpp new file mode 100644 index 0000000..d106868 --- /dev/null +++ b/12_graph/39_paths_to_travel_each_node_using_each_edge_seven_bridge.cpp @@ -0,0 +1,92 @@ +/* + link (just refer): https://www.geeksforgeeks.org/paths-travel-nodes-using-edgeseven-bridges-konigsberg/ + + video: https://youtu.be/WY6Jsp3NxIk +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +//TIME COMPLEXITY: O(V+E) +#include +using namespace std; +#define V 5 +#define pb push_back + +unordered_map> adj; + +void DFS(int curr, vector& visited) +{ + visited[curr] = true; + for (auto it : adj[curr]) + { + if (!visited[it]) + DFS(it, visited); + } +} + +bool Connected_Graph() +{ + vector visited(V + 1, false); + int node = -1; //Node to start DFS + for (int i = 0;i < V;++i) + if (adj[i].size() > 0) + { + node = i; //Found a node to start DFS + break; + } + if (node == -1) //No start node was found-->No edges are present in graph + return true; //It's always Eulerian + + DFS(node, visited); + //Check if all the non-zero vertices are visited + for (int i = 0;i < V;++i) + if (visited[i] == false and adj[i].size() > 0) + return false; //We have edges in multi-component + return true; +} + +int find_Euler() +{ + if (!Connected_Graph()) //multi-component edged graph + return 0; //All non-zero degree vertices should be connected + + //Count odd-degree vertices + int odd = 0; + for (int i = 0;i < V;++i) + if (adj[i].size() & 1) + odd += 1; + + if (odd > 2) //Only start and end node can have odd degree + return 0; + + return (odd == 0) ? 2 : 1; //1->Semi-Eulerian...2->Eulerian +} + +void findEuler_Path_Cycle() +{ + int ret = find_Euler(); + if (ret == 0) + cout << "Graph is NOT a Euler graph\n"; + else if (ret == 1) + cout << "Graph is Semi-Eulerian\n"; + else + cout << "Graph is Eulerian (Euler circuit)\n"; +} + +int main() +{ + adj[0].pb(1); + adj[1].pb(0); + adj[0].pb(2); + adj[2].pb(0); + adj[2].pb(1); + adj[1].pb(2); + adj[0].pb(3); + adj[3].pb(0); + adj[3].pb(4); + adj[4].pb(3); + findEuler_Path_Cycle(); + + return 0; +} diff --git a/12_graph/40_vertex_cover_problem.cpp b/12_graph/40_vertex_cover_problem.cpp new file mode 100644 index 0000000..71a7e67 --- /dev/null +++ b/12_graph/40_vertex_cover_problem.cpp @@ -0,0 +1,105 @@ +/* + link: https://www.geeksforgeeks.org/vertex-cover-problem-set-1-introduction-approximate-algorithm-2/ + + Given an undirected graph, the vertex cover problem is to find minimum size vertex cover + means min. no. of vertices which cover every edges + + note from GFG: We will soon be discussing exact algorithms for vertex cover. + + as this code doesn't give exact minimal solution +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(V + E) + + this code is just for ref. (it's not exact code) +*/ +// Program to print Vertex Cover of a given undirected graph +#include +#include +using namespace std; + +// This class represents a undirected graph using adjacency list +class Graph +{ + int V; // No. of vertices + list* adj; // Pointer to an array containing adjacency lists +public: + Graph(int V); // Constructor + void addEdge(int v, int w); // function to add an edge to graph + void printVertexCover(); // prints vertex cover +}; + +Graph::Graph(int V) +{ + this->V = V; + adj = new list[V]; +} + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); // Add w to v’s list. + adj[w].push_back(v); // Since the graph is undirected +} + +// The function to print vertex cover +void Graph::printVertexCover() +{ + // Initialize all vertices as not visited. + bool visited[V]; + for (int i = 0; i < V; i++) + visited[i] = false; + + list::iterator i; + + // Consider all edges one by one + for (int u = 0; u < V; u++) + { + // An edge is only picked when both visited[u] and visited[v] + // are false + if (visited[u] == false) + { + // Go through all adjacents of u and pick the first not + // yet visited vertex (We are basically picking an edge + // (u, v) from remaining edges. + for (i = adj[u].begin(); i != adj[u].end(); ++i) + { + int v = *i; + if (visited[v] == false) + { + // Add the vertices (u, v) to the result set. + // We make the vertex u and v visited so that + // all edges from/to them would be ignored + visited[v] = true; + visited[u] = true; + break; + } + } + } + } + + // Print the vertex cover + for (int i = 0; i < V; i++) + if (visited[i]) + cout << i << " "; +} + +// Driver program to test methods of graph class +int main() +{ + // Create a graph given in the above diagram + Graph g(7); + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(1, 3); + g.addEdge(3, 4); + g.addEdge(4, 5); + g.addEdge(5, 6); + + g.printVertexCover(); + + return 0; +} diff --git a/12_graph/41_chinese_postman_or_route_inspection.cpp b/12_graph/41_chinese_postman_or_route_inspection.cpp new file mode 100644 index 0000000..f165ba7 --- /dev/null +++ b/12_graph/41_chinese_postman_or_route_inspection.cpp @@ -0,0 +1,18 @@ +/* + link: https://www.geeksforgeeks.org/chinese-postman-route-inspection-set-1-introduction/ + + Algorithm is to find shortest closed path or optimal + Chinese postman route in a weighted graph that may + not be Eulerian. + + algo: + if(eulerian circuit) { + => return the total weight of whole graph + } + else { + => find all the odd degree vertex + => for each pairing find shortest path connecting them + => so, total weight = total weight + total_weight_of_shortest_path_odd_degree_pair; + } + +*/ diff --git a/12_graph/42_no_of_triangle_in_directed_or_undirected_graphs.cpp b/12_graph/42_no_of_triangle_in_directed_or_undirected_graphs.cpp new file mode 100644 index 0000000..d62ca72 --- /dev/null +++ b/12_graph/42_no_of_triangle_in_directed_or_undirected_graphs.cpp @@ -0,0 +1,91 @@ +/* + link: https://www.geeksforgeeks.org/number-of-triangles-in-directed-and-undirected-graphs/ + [for both dir. and undir. graph] + + problem can also be done using DFS [but complexity will remain same] + (maintain the parent of curr and while iterating for curr's adjacent, check if curr's adjacent has parent as its adjacent) + + + link [for undirected graph]: https://www.geeksforgeeks.org/number-of-triangles-in-a-undirected-graph/ + note: read ** how does this work ? ** +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + The time complexity is O(n^3) and can’t be reduced any further. +*/ +// C++ program to count triangles +// in a graph. The program is for +// adjacency matrix representation +// of the graph. +#include + +// Number of vertices in the graph +#define V 4 + +using namespace std; + +// function to calculate the +// number of triangles in a +// simple directed/undirected +// graph. isDirected is true if +// the graph is directed, its +// false otherwise +int countTriangle(int graph[V][V], + bool isDirected) +{ + // Initialize result + int count_Triangle = 0; + + // Consider every possible + // triplet of edges in graph + for (int i = 0; i < V; i++) + { + for (int j = 0; j < V; j++) + { + for (int k = 0; k < V; k++) + { + // Check the triplet if + // it satisfies the condition + if (graph[i][j] && graph[j][k] + && graph[k][i]) + count_Triangle++; + } + } + } + + // If graph is directed , + // division is done by 3, + // else division by 6 is done as each triangle would have counted twice (clockwise and anti-clockwise) + isDirected ? count_Triangle /= 3 : count_Triangle /= 6; + + return count_Triangle; +} + +//driver function to check the program +int main() +{ + // Create adjacency matrix + // of an undirected graph + int graph[][V] = { {0, 1, 1, 0}, + {1, 0, 1, 1}, + {1, 1, 0, 1}, + {0, 1, 1, 0} + }; + +// Create adjacency matrix +// of a directed graph + int digraph[][V] = { {0, 0, 1, 0}, + {1, 0, 0, 1}, + {0, 1, 0, 0}, + {0, 0, 1, 0} + }; + + cout << "The Number of triangles in undirected graph : " + << countTriangle(graph, false); + cout << "\n\nThe Number of triangles in directed graph : " + << countTriangle(digraph, true); + + return 0; +} diff --git a/12_graph/43_Minimize_Cash_Flow_among_a_given_set_of_friends_who_have_borrowed_money_from_each_other.cpp b/12_graph/43_Minimize_Cash_Flow_among_a_given_set_of_friends_who_have_borrowed_money_from_each_other.cpp new file mode 100644 index 0000000..5326db2 --- /dev/null +++ b/12_graph/43_Minimize_Cash_Flow_among_a_given_set_of_friends_who_have_borrowed_money_from_each_other.cpp @@ -0,0 +1,5 @@ +/* + link [greedy]: https://www.geeksforgeeks.org/minimize-cash-flow-among-given-set-friends-borrowed-money/ + + ref: greedy/11/min_cash_flow... +*/ \ No newline at end of file diff --git a/12_graph/44_two_clique_problem.cpp b/12_graph/44_two_clique_problem.cpp new file mode 100644 index 0000000..b5feae7 --- /dev/null +++ b/12_graph/44_two_clique_problem.cpp @@ -0,0 +1,122 @@ +/* + link: https://www.geeksforgeeks.org/two-clique-problem-check-graph-can-divided-two-cliques/ + + video: https://youtu.be/cA8-mdRJuCI + why to complement and use bipartite? see [3:42] image in above video to understand + + complement: means every node will now be connected to other clique + bipartite: now to make sure that it is possible to color + + hence we can divide the graph in 2 clique +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// Time complexity of above implementation is O(V^2) + +// C++ program to find out whether a given graph can be +// converted to two Cliques or not. +#include +using namespace std; + +const int V = 5; + +// This function returns true if subgraph reachable from +// src is Bipartite or not. +bool isBipartiteUtil(int G[][V], int src, int colorArr[]) +{ + colorArr[src] = 1; + + // Create a queue (FIFO) of vertex numbers and enqueue + // source vertex for BFS traversal + queue q; + q.push(src); + + // Run while there are vertices in queue (Similar to BFS) + while (!q.empty()) + { + // Dequeue a vertex from queue + int u = q.front(); + q.pop(); + + // Find all non-colored adjacent vertices + for (int v = 0; v < V; ++v) + { + // An edge from u to v exists and destination + // v is not colored + if (G[u][v] && colorArr[v] == -1) + { + // Assign alternate color to this adjacent + // v of u + colorArr[v] = 1 - colorArr[u]; + q.push(v); + } + + // An edge from u to v exists and destination + // v is colored with same color as u + else if (G[u][v] && colorArr[v] == colorArr[u]) + return false; + } + } + + // If we reach here, then all adjacent vertices can + // be colored with alternate color + return true; +} + +// Returns true if a Graph G[][] is Bipartite or not. Note +// that G may not be connected. +bool isBipartite(int G[][V]) +{ + // Create a color array to store colors assigned + // to all veritces. Vertex number is used as index in + // this array. The value '-1' of colorArr[i] + // is used to indicate that no color is assigned to + // vertex 'i'. The value 1 is used to indicate first + // color is assigned and value 0 indicates + // second color is assigned. + int colorArr[V]; + for (int i = 0; i < V; ++i) + colorArr[i] = -1; + + // One by one check all not yet colored vertices. + for (int i = 0; i < V; i++) + if (colorArr[i] == -1) + if (isBipartiteUtil(G, i, colorArr) == false) + return false; + + return true; +} + +// Returns true if G can be divided into +// two Cliques, else false. +bool canBeDividedinTwoCliques(int G[][V]) +{ + // Find complement of G[][] + // All values are complemented except + // diagonal ones + int GC[V][V]; + for (int i = 0; i < V; i++) + for (int j = 0; j < V; j++) + GC[i][j] = (i != j) ? !G[i][j] : 0; + + // Return true if complement is Bipartite + // else false. + return isBipartite(GC); +} + +// Driver program to test above function +int main() +{ + int G[][V] = { {0, 1, 1, 1, 0}, + {1, 0, 1, 0, 0}, + {1, 1, 0, 0, 0}, + {0, 1, 0, 0, 1}, + {0, 0, 0, 1, 0} + }; + + canBeDividedinTwoCliques(G) ? cout << "Yes" : + cout << "No"; + return 0; +} diff --git a/12_graph/extra_01_shortest_path_in_undirected_graph_with_unit_weight.cpp b/12_graph/extra_01_shortest_path_in_undirected_graph_with_unit_weight.cpp new file mode 100644 index 0000000..6b1d674 --- /dev/null +++ b/12_graph/extra_01_shortest_path_in_undirected_graph_with_unit_weight.cpp @@ -0,0 +1,40 @@ +/* + video: https://youtu.be/hwCWi7-bRfI?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + + if we use DFS then we have to pass level+1 in recursive function +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS + TC: O(V + E) + SC: O(V) + O(V) + + we can get shortest distance between src to any node. +*/ +void BFS(vector adj[], int N, int src) +{ + int dist[N]; + for (int i = 0;i < N;i++) dist[i] = INT_MAX; + queue q; + + dist[src] = 0; + q.push(src); + + while (q.empty() == false) + { + int node = q.front(); + q.pop(); + + for (auto it : adj[node]) { + if (dist[node] + 1 < dist[it]) { + dist[it] = dist[node] + 1; + q.push(it); + } + } + } + for (int i = 0;i < N;i++) cout << dist[i] << " "; + +} \ No newline at end of file diff --git a/12_graph/extra_02_shortest_path_in_DAG_with_weight.cpp b/12_graph/extra_02_shortest_path_in_DAG_with_weight.cpp new file mode 100644 index 0000000..1b59517 --- /dev/null +++ b/12_graph/extra_02_shortest_path_in_DAG_with_weight.cpp @@ -0,0 +1,84 @@ +/* + video: https://youtu.be/CrxG4WJotgg?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + 1. find topological sort + 2. make dist array + 3. mark src in dist as 0 + 4. from stack made using topological sort pop 1 by 1 ele. + 5. update dist. array as dis[curr] = dis[prev] + 1 + +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using BFS + + TC: O(V + E) + SC: O(2*V) +*/ +#include +#define INF INT_MAX +using namespace std; + +void findTopoSort(int node, int vis[], stack& st, vector> adj[]) { + vis[node] = 1; + for (auto it : adj[node]) { + if (!vis[it.first]) { + findTopoSort(it.first, vis, st, adj); + } + } + st.push(node); +} + + +void shortestPath(int src, int N, vector> adj[]) +{ + int vis[N] = { 0 }; + stack st; + for (int i = 0; i < N; i++) + if (!vis[i]) + findTopoSort(i, vis, st, adj); + + int dist[N]; + for (int i = 0; i < N; i++) + dist[i] = 1e9; + + // crucial step + dist[src] = 0; + + while (!st.empty()) + { + int node = st.top(); + st.pop(); + + if (dist[node] != INF) { + for (auto it : adj[node]) { + // prev cost + curr node's weight < curr cost + if (dist[node] + it.second < dist[it.first]) { + dist[it.first] = dist[node] + it.second; + } + } + } + } + + for (int i = 0; i < N; i++) + (dist[i] == 1e9) ? cout << "INF " : cout << dist[i] << " "; +} + +int main() +{ + int n, m; + cin >> n >> m; + vector> adj[n]; + for (int i = 0;i < m;i++) { + int u, v, wt; + cin >> u >> v >> wt; + adj[u].push_back({ v, wt }); + } + + shortestPath(0, n, adj); + + return 0; +} \ No newline at end of file diff --git a/12_graph/extra_03_disjoint_set_union_by_rank_and_path_compression.cpp b/12_graph/extra_03_disjoint_set_union_by_rank_and_path_compression.cpp new file mode 100644 index 0000000..c1e3f0c --- /dev/null +++ b/12_graph/extra_03_disjoint_set_union_by_rank_and_path_compression.cpp @@ -0,0 +1,75 @@ +/* + what is disjoint set ? + what is union by rank ? + what is path compression ? + https://www.geeksforgeeks.org/disjoint-set-data-structures/ + https://www.geeksforgeeks.org/union-find-algorithm-set-2-union-by-rank/ + + Partitioning the individuals into different sets according to the groups + in which they fall. This method is known as disjoint set data structure which + maintains collection of disjoint sets and each set is represented by its + representative which is one of its members. + + video: https://youtu.be/3gbO7FDYNFQ?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(4 * alpha) => approx. O(4) constant time +*/ + +int parent[1e5]; +int rank[1e5]; + +static int N; + +void makeSet() { + for (int i = 0;i < N;i++) { + parent[i] = i; + rank[i] = 0; + } +} + +int findPar(int node) { + if (node == parent[node]) return node; + + // here it's path compression + return parent[node] = findPar(parent[node]); +} + +// union by rank +void union(int u, int v) { + u = findPar(u); + v = findPar(v); + + if (rank[u] < rank[v]) { + parent[u] = v; + } + else if (rank[u] > rank[v]) parent[v] = u; + else { + parent[v] = u; + rank[u]++; + } +} + + +int main() { + cin >> N; + + makeSet(); + + // if given M operation + int M; + cin >> M; + while (M--) { + int u, v; + cin >> u >> v; + union(u, v); + } + + // if we want to check 2 and 3 belong to same component or not + if (findPar(2) == findPar(3)) cout << "same component" << endl; + else cout << "different component" << endl; + +} \ No newline at end of file diff --git a/12_graph/extra_04_articulation_point_(cut_vertex).cpp b/12_graph/extra_04_articulation_point_(cut_vertex).cpp new file mode 100644 index 0000000..4524352 --- /dev/null +++ b/12_graph/extra_04_articulation_point_(cut_vertex).cpp @@ -0,0 +1,77 @@ +/* + sol: https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/ + + video: https://youtu.be/3t3JHswP7mw?list=PLgUwDviBIf0rGEWe64KWas0Nryn7SCRWw + + ref: 26/find bridge in graph .cpp + + + use hashSet as articulation point can come multiple time +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(V + E) + SC: O(V) + O(V) + O(V) + O(V), for vis, tin, low, isArti... +*/ +#include +using namespace std; +void dfs(int node, int parent, vector& vis, vector& tin, vector& low, int& timer, vector adj[], vector& isArticulation) { + vis[node] = 1; + tin[node] = low[node] = timer++; + int child = 0; + for (auto it : adj[node]) { + if (it == parent) continue; + + if (!vis[it]) { + dfs(it, node, vis, tin, low, timer, adj, isArticulation); + low[node] = min(low[node], low[it]); + + // from here we can know that this node has multiple child and are not connected + // bcoz if they would have they have already been visited + child++; + if (low[it] >= tin[node] && parent != -1) { + isArticulation[node] = 1; + } + } + else { + // if the node is visited means it cannot be articulation point + // hence so improve the low[node] if the adjacent's insertion time is lesser + low[node] = min(low[node], tin[it]); + } + } + + if (parent == -1 && child > 1) { + isArticulation[node] = 1; + } +} +int main() { + int n, m; + cin >> n >> m; + vector adj[n]; + for (int i = 0;i < m;i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } + + vector tin(n, -1); + vector low(n, -1); + vector vis(n, 0); + vector isArticulation(n, 0); + int timer = 0; + for (int i = 0;i < n;i++) { + if (!vis[i]) { + dfs(i, -1, vis, tin, low, timer, adj, isArticulation); + } + } + + for (int i = 0;i < n;i++) { + if (isArticulation[i] == 1) cout << i << endl; + } + + return 0; +} \ No newline at end of file