From bc7649faec55e9f3e93ef7dd047e0ab5020cfb80 Mon Sep 17 00:00:00 2001 From: Reshad-Hasan Date: Sun, 24 Feb 2019 19:45:08 +0600 Subject: [PATCH 1/4] organized graph algorithms --- {Graphs => graph algorithms}/BFS.py | 0 {Graphs => graph algorithms}/DFS.py | 0 .../Directed and Undirected (Weighted) Graph.py | 0 {graphs => graph algorithms}/a_star.py | 0 {graphs => graph algorithms}/articulation_points.py | 0 {graphs => graph algorithms}/basic_graphs.py | 0 {data_structures/graph => graph algorithms}/bellman_ford.py | 0 .../graph => graph algorithms}/breadth_first_search.py | 0 {graphs => graph algorithms}/check_bipartite_graph_bfs.py | 0 {data_structures/graph => graph algorithms}/depth_first_search.py | 0 {graphs => graph algorithms}/dijkstra.py | 0 .../graph/dijkstra.py => graph algorithms/dijkstra_2.py | 0 {data_structures/graph => graph algorithms}/dijkstra_algorithm.py | 0 {data_structures/graph => graph algorithms}/even_tree.py | 0 {graphs => graph algorithms}/finding_bridges.py | 0 {data_structures/graph => graph algorithms}/floyd_warshall.py | 0 {data_structures/graph => graph algorithms}/graph.py | 0 {data_structures/graph => graph algorithms}/graph_list.py | 0 {data_structures/graph => graph algorithms}/graph_matrix.py | 0 {graphs => graph algorithms}/kahns_algorithm_long.py | 0 {graphs => graph algorithms}/kahns_algorithm_topo.py | 0 {graphs => graph algorithms}/minimum_spanning_tree_kruskal.py | 0 {graphs => graph algorithms}/minimum_spanning_tree_prims.py | 0 {graphs => graph algorithms}/multi_hueristic_astar.py | 0 {graphs => graph algorithms}/scc_kosaraju.py | 0 {graphs => graph algorithms}/tarjans_scc.py | 0 factorial_python.py => number theory/factorial_python.py | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename {Graphs => graph algorithms}/BFS.py (100%) rename {Graphs => graph algorithms}/DFS.py (100%) rename {graphs => graph algorithms}/Directed and Undirected (Weighted) Graph.py (100%) rename {graphs => graph algorithms}/a_star.py (100%) rename {graphs => graph algorithms}/articulation_points.py (100%) rename {graphs => graph algorithms}/basic_graphs.py (100%) rename {data_structures/graph => graph algorithms}/bellman_ford.py (100%) rename {data_structures/graph => graph algorithms}/breadth_first_search.py (100%) rename {graphs => graph algorithms}/check_bipartite_graph_bfs.py (100%) rename {data_structures/graph => graph algorithms}/depth_first_search.py (100%) rename {graphs => graph algorithms}/dijkstra.py (100%) rename data_structures/graph/dijkstra.py => graph algorithms/dijkstra_2.py (100%) rename {data_structures/graph => graph algorithms}/dijkstra_algorithm.py (100%) rename {data_structures/graph => graph algorithms}/even_tree.py (100%) rename {graphs => graph algorithms}/finding_bridges.py (100%) rename {data_structures/graph => graph algorithms}/floyd_warshall.py (100%) rename {data_structures/graph => graph algorithms}/graph.py (100%) rename {data_structures/graph => graph algorithms}/graph_list.py (100%) rename {data_structures/graph => graph algorithms}/graph_matrix.py (100%) rename {graphs => graph algorithms}/kahns_algorithm_long.py (100%) rename {graphs => graph algorithms}/kahns_algorithm_topo.py (100%) rename {graphs => graph algorithms}/minimum_spanning_tree_kruskal.py (100%) rename {graphs => graph algorithms}/minimum_spanning_tree_prims.py (100%) rename {graphs => graph algorithms}/multi_hueristic_astar.py (100%) rename {graphs => graph algorithms}/scc_kosaraju.py (100%) rename {graphs => graph algorithms}/tarjans_scc.py (100%) rename factorial_python.py => number theory/factorial_python.py (100%) diff --git a/Graphs/BFS.py b/graph algorithms/BFS.py similarity index 100% rename from Graphs/BFS.py rename to graph algorithms/BFS.py diff --git a/Graphs/DFS.py b/graph algorithms/DFS.py similarity index 100% rename from Graphs/DFS.py rename to graph algorithms/DFS.py diff --git a/graphs/Directed and Undirected (Weighted) Graph.py b/graph algorithms/Directed and Undirected (Weighted) Graph.py similarity index 100% rename from graphs/Directed and Undirected (Weighted) Graph.py rename to graph algorithms/Directed and Undirected (Weighted) Graph.py diff --git a/graphs/a_star.py b/graph algorithms/a_star.py similarity index 100% rename from graphs/a_star.py rename to graph algorithms/a_star.py diff --git a/graphs/articulation_points.py b/graph algorithms/articulation_points.py similarity index 100% rename from graphs/articulation_points.py rename to graph algorithms/articulation_points.py diff --git a/graphs/basic_graphs.py b/graph algorithms/basic_graphs.py similarity index 100% rename from graphs/basic_graphs.py rename to graph algorithms/basic_graphs.py diff --git a/data_structures/graph/bellman_ford.py b/graph algorithms/bellman_ford.py similarity index 100% rename from data_structures/graph/bellman_ford.py rename to graph algorithms/bellman_ford.py diff --git a/data_structures/graph/breadth_first_search.py b/graph algorithms/breadth_first_search.py similarity index 100% rename from data_structures/graph/breadth_first_search.py rename to graph algorithms/breadth_first_search.py diff --git a/graphs/check_bipartite_graph_bfs.py b/graph algorithms/check_bipartite_graph_bfs.py similarity index 100% rename from graphs/check_bipartite_graph_bfs.py rename to graph algorithms/check_bipartite_graph_bfs.py diff --git a/data_structures/graph/depth_first_search.py b/graph algorithms/depth_first_search.py similarity index 100% rename from data_structures/graph/depth_first_search.py rename to graph algorithms/depth_first_search.py diff --git a/graphs/dijkstra.py b/graph algorithms/dijkstra.py similarity index 100% rename from graphs/dijkstra.py rename to graph algorithms/dijkstra.py diff --git a/data_structures/graph/dijkstra.py b/graph algorithms/dijkstra_2.py similarity index 100% rename from data_structures/graph/dijkstra.py rename to graph algorithms/dijkstra_2.py diff --git a/data_structures/graph/dijkstra_algorithm.py b/graph algorithms/dijkstra_algorithm.py similarity index 100% rename from data_structures/graph/dijkstra_algorithm.py rename to graph algorithms/dijkstra_algorithm.py diff --git a/data_structures/graph/even_tree.py b/graph algorithms/even_tree.py similarity index 100% rename from data_structures/graph/even_tree.py rename to graph algorithms/even_tree.py diff --git a/graphs/finding_bridges.py b/graph algorithms/finding_bridges.py similarity index 100% rename from graphs/finding_bridges.py rename to graph algorithms/finding_bridges.py diff --git a/data_structures/graph/floyd_warshall.py b/graph algorithms/floyd_warshall.py similarity index 100% rename from data_structures/graph/floyd_warshall.py rename to graph algorithms/floyd_warshall.py diff --git a/data_structures/graph/graph.py b/graph algorithms/graph.py similarity index 100% rename from data_structures/graph/graph.py rename to graph algorithms/graph.py diff --git a/data_structures/graph/graph_list.py b/graph algorithms/graph_list.py similarity index 100% rename from data_structures/graph/graph_list.py rename to graph algorithms/graph_list.py diff --git a/data_structures/graph/graph_matrix.py b/graph algorithms/graph_matrix.py similarity index 100% rename from data_structures/graph/graph_matrix.py rename to graph algorithms/graph_matrix.py diff --git a/graphs/kahns_algorithm_long.py b/graph algorithms/kahns_algorithm_long.py similarity index 100% rename from graphs/kahns_algorithm_long.py rename to graph algorithms/kahns_algorithm_long.py diff --git a/graphs/kahns_algorithm_topo.py b/graph algorithms/kahns_algorithm_topo.py similarity index 100% rename from graphs/kahns_algorithm_topo.py rename to graph algorithms/kahns_algorithm_topo.py diff --git a/graphs/minimum_spanning_tree_kruskal.py b/graph algorithms/minimum_spanning_tree_kruskal.py similarity index 100% rename from graphs/minimum_spanning_tree_kruskal.py rename to graph algorithms/minimum_spanning_tree_kruskal.py diff --git a/graphs/minimum_spanning_tree_prims.py b/graph algorithms/minimum_spanning_tree_prims.py similarity index 100% rename from graphs/minimum_spanning_tree_prims.py rename to graph algorithms/minimum_spanning_tree_prims.py diff --git a/graphs/multi_hueristic_astar.py b/graph algorithms/multi_hueristic_astar.py similarity index 100% rename from graphs/multi_hueristic_astar.py rename to graph algorithms/multi_hueristic_astar.py diff --git a/graphs/scc_kosaraju.py b/graph algorithms/scc_kosaraju.py similarity index 100% rename from graphs/scc_kosaraju.py rename to graph algorithms/scc_kosaraju.py diff --git a/graphs/tarjans_scc.py b/graph algorithms/tarjans_scc.py similarity index 100% rename from graphs/tarjans_scc.py rename to graph algorithms/tarjans_scc.py diff --git a/factorial_python.py b/number theory/factorial_python.py similarity index 100% rename from factorial_python.py rename to number theory/factorial_python.py From 1a0b3eb6c9c6f7e8ab58babd83244222d22b2c61 Mon Sep 17 00:00:00 2001 From: Reshad-Hasan Date: Mon, 25 Feb 2019 14:26:58 +0600 Subject: [PATCH 2/4] all graph algorithms in Graphs/ folder --- Graphs/BFS.py | 39 ++ Graphs/DFS.py | 36 ++ ...irected and Undirected (Weighted) Graph.py | 468 ++++++++++++++++++ Graphs/a_star.py | 102 ++++ Graphs/articulation_points.py | 44 ++ Graphs/basic_graphs.py | 290 +++++++++++ Graphs/bellman_ford.py | 54 ++ Graphs/breadth_first_search.py | 67 +++ Graphs/check_bipartite_graph_bfs.py | 43 ++ Graphs/depth_first_search.py | 66 +++ Graphs/dijkstra.py | 47 ++ Graphs/dijkstra_2.py | 57 +++ Graphs/dijkstra_algorithm.py | 212 ++++++++ Graphs/even_tree.py | 70 +++ Graphs/finding_bridges.py | 31 ++ Graphs/floyd_warshall.py | 48 ++ Graphs/graph.py | 44 ++ Graphs/graph_list.py | 31 ++ Graphs/graph_matrix.py | 32 ++ Graphs/kahns_algorithm_long.py | 30 ++ Graphs/kahns_algorithm_topo.py | 32 ++ Graphs/minimum_spanning_tree_kruskal.py | 32 ++ Graphs/minimum_spanning_tree_prims.py | 111 +++++ Graphs/multi_hueristic_astar.py | 266 ++++++++++ Graphs/scc_kosaraju.py | 46 ++ Graphs/tarjans_scc.py | 78 +++ 26 files changed, 2376 insertions(+) create mode 100644 Graphs/BFS.py create mode 100644 Graphs/DFS.py create mode 100644 Graphs/Directed and Undirected (Weighted) Graph.py create mode 100644 Graphs/a_star.py create mode 100644 Graphs/articulation_points.py create mode 100644 Graphs/basic_graphs.py create mode 100644 Graphs/bellman_ford.py create mode 100644 Graphs/breadth_first_search.py create mode 100644 Graphs/check_bipartite_graph_bfs.py create mode 100644 Graphs/depth_first_search.py create mode 100644 Graphs/dijkstra.py create mode 100644 Graphs/dijkstra_2.py create mode 100644 Graphs/dijkstra_algorithm.py create mode 100644 Graphs/even_tree.py create mode 100644 Graphs/finding_bridges.py create mode 100644 Graphs/floyd_warshall.py create mode 100644 Graphs/graph.py create mode 100644 Graphs/graph_list.py create mode 100644 Graphs/graph_matrix.py create mode 100644 Graphs/kahns_algorithm_long.py create mode 100644 Graphs/kahns_algorithm_topo.py create mode 100644 Graphs/minimum_spanning_tree_kruskal.py create mode 100644 Graphs/minimum_spanning_tree_prims.py create mode 100644 Graphs/multi_hueristic_astar.py create mode 100644 Graphs/scc_kosaraju.py create mode 100644 Graphs/tarjans_scc.py diff --git a/Graphs/BFS.py b/Graphs/BFS.py new file mode 100644 index 000000000000..bf9b572cec50 --- /dev/null +++ b/Graphs/BFS.py @@ -0,0 +1,39 @@ +"""pseudo-code""" + +""" +BFS(graph G, start vertex s): +// all nodes initially unexplored +mark s as explored +let Q = queue data structure, initialized with s +while Q is non-empty: + remove the first node of Q, call it v + for each edge(v, w): // for w in graph[v] + if w unexplored: + mark w as explored + add w to Q (at the end) + +""" + +import collections + + +def bfs(graph, start): + explored, queue = set(), [start] # collections.deque([start]) + explored.add(start) + while queue: + v = queue.pop(0) # queue.popleft() + for w in graph[v]: + if w not in explored: + explored.add(w) + queue.append(w) + return explored + + +G = {'A': ['B', 'C'], + 'B': ['A', 'D', 'E'], + 'C': ['A', 'F'], + 'D': ['B'], + 'E': ['B', 'F'], + 'F': ['C', 'E']} + +print(bfs(G, 'A')) diff --git a/Graphs/DFS.py b/Graphs/DFS.py new file mode 100644 index 000000000000..d3c34fabb7b3 --- /dev/null +++ b/Graphs/DFS.py @@ -0,0 +1,36 @@ +"""pseudo-code""" + +""" +DFS(graph G, start vertex s): +// all nodes initially unexplored +mark s as explored +for every edge (s, v): + if v unexplored: + DFS(G, v) +""" + + +def dfs(graph, start): + """The DFS function simply calls itself recursively for every unvisited child of its argument. We can emulate that + behaviour precisely using a stack of iterators. Instead of recursively calling with a node, we'll push an iterator + to the node's children onto the iterator stack. When the iterator at the top of the stack terminates, we'll pop + it off the stack.""" + explored, stack = set(), [start] + explored.add(start) + while stack: + v = stack.pop() # the only difference from BFS is to pop last element here instead of first one + for w in graph[v]: + if w not in explored: + explored.add(w) + stack.append(w) + return explored + + +G = {'A': ['B', 'C'], + 'B': ['A', 'D', 'E'], + 'C': ['A', 'F'], + 'D': ['B'], + 'E': ['B', 'F'], + 'F': ['C', 'E']} + +print(dfs(G, 'A')) diff --git a/Graphs/Directed and Undirected (Weighted) Graph.py b/Graphs/Directed and Undirected (Weighted) Graph.py new file mode 100644 index 000000000000..68977de8d311 --- /dev/null +++ b/Graphs/Directed and Undirected (Weighted) Graph.py @@ -0,0 +1,468 @@ +from collections import deque +import random as rand +import math as math +import time + +# the dfault weight is 1 if not assigend but all the implementation is weighted + +class DirectedGraph: + def __init__(self): + self.graph = {} + + # adding vertices and edges + # adding the weight is optional + # handels repetition + def add_pair(self, u, v, w = 1): + if self.graph.get(u): + if self.graph[u].count([w,v]) == 0: + self.graph[u].append([w, v]) + else: + self.graph[u] = [[w, v]] + if not self.graph.get(v): + self.graph[v] = [] + + def all_nodes(self): + return list(self.graph) + + # handels if the input does not exist + def remove_pair(self, u, v): + if self.graph.get(u): + for _ in self.graph[u]: + if _[1] == v: + self.graph[u].remove(_) + + # if no destination is meant the defaut value is -1 + def dfs(self, s = -2, d = -1): + if s == d: + return [] + stack = [] + visited = [] + if s == -2: + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + ss = s + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) < 1: + if __[1] == d: + visited.append(d) + return visited + else: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return visited + + # c is the count of nodes you want and if you leave it or pass -1 to the funtion the count + # will be random from 10 to 10000 + def fill_graph_randomly(self, c = -1): + if c == -1: + c = (math.floor(rand.random() * 10000)) + 10 + for _ in range(c): + # every vertex has max 100 edges + e = math.floor(rand.random() * 102) + 1 + for __ in range(e): + n = math.floor(rand.random() * (c)) + 1 + if n == _: + continue + self.add_pair(_, n, 1) + + def bfs(self, s = -2): + d = deque() + visited = [] + if s == -2: + s = list(self.graph.keys())[0] + d.append(s) + visited.append(s) + while d: + s = d.popleft() + if len(self.graph[s]) != 0: + for __ in self.graph[s]: + if visited.count(__[1]) < 1: + d.append(__[1]) + visited.append(__[1]) + return visited + def in_degree(self, u): + count = 0 + for _ in self.graph: + for __ in self.graph[_]: + if __[1] == u: + count += 1 + return count + + def out_degree(self, u): + return len(self.graph[u]) + + def topological_sort(self, s = -2): + stack = [] + visited = [] + if s == -2: + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + ss = s + sorted_nodes = [] + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) < 1: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + sorted_nodes.append(stack.pop()) + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return sorted_nodes + + def cycle_nodes(self): + stack = [] + visited = [] + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: + l = len(stack) - 1 + while True and l >= 0: + if stack[l] == __[1]: + anticipating_nodes.add(__[1]) + break + else: + anticipating_nodes.add(stack[l]) + l -= 1 + if visited.count(__[1]) < 1: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return list(anticipating_nodes) + + def has_cycle(self): + stack = [] + visited = [] + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: + l = len(stack) - 1 + while True and l >= 0: + if stack[l] == __[1]: + anticipating_nodes.add(__[1]) + break + else: + return True + anticipating_nodes.add(stack[l]) + l -= 1 + if visited.count(__[1]) < 1: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return False + + def dfs_time(self, s = -2, e = -1): + begin = time.time() + self.dfs(s,e) + end = time.time() + return end - begin + + def bfs_time(self, s = -2): + begin = time.time() + self.bfs(s) + end = time.time() + return end - begin + +class Graph: + def __init__(self): + self.graph = {} + + # adding vertices and edges + # adding the weight is optional + # handels repetition + def add_pair(self, u, v, w = 1): + # check if the u exists + if self.graph.get(u): + # if there already is a edge + if self.graph[u].count([w,v]) == 0: + self.graph[u].append([w, v]) + else: + # if u does not exist + self.graph[u] = [[w, v]] + # add the other way + if self.graph.get(v): + # if there already is a edge + if self.graph[v].count([w,u]) == 0: + self.graph[v].append([w, u]) + else: + # if u does not exist + self.graph[v] = [[w, u]] + + # handels if the input does not exist + def remove_pair(self, u, v): + if self.graph.get(u): + for _ in self.graph[u]: + if _[1] == v: + self.graph[u].remove(_) + # the other way round + if self.graph.get(v): + for _ in self.graph[v]: + if _[1] == u: + self.graph[v].remove(_) + + # if no destination is meant the defaut value is -1 + def dfs(self, s = -2, d = -1): + if s == d: + return [] + stack = [] + visited = [] + if s == -2: + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + ss = s + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) < 1: + if __[1] == d: + visited.append(d) + return visited + else: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return visited + + # c is the count of nodes you want and if you leave it or pass -1 to the funtion the count + # will be random from 10 to 10000 + def fill_graph_randomly(self, c = -1): + if c == -1: + c = (math.floor(rand.random() * 10000)) + 10 + for _ in range(c): + # every vertex has max 100 edges + e = math.floor(rand.random() * 102) + 1 + for __ in range(e): + n = math.floor(rand.random() * (c)) + 1 + if n == _: + continue + self.add_pair(_, n, 1) + + def bfs(self, s = -2): + d = deque() + visited = [] + if s == -2: + s = list(self.graph.keys())[0] + d.append(s) + visited.append(s) + while d: + s = d.popleft() + if len(self.graph[s]) != 0: + for __ in self.graph[s]: + if visited.count(__[1]) < 1: + d.append(__[1]) + visited.append(__[1]) + return visited + def degree(self, u): + return len(self.graph[u]) + + def cycle_nodes(self): + stack = [] + visited = [] + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: + l = len(stack) - 1 + while True and l >= 0: + if stack[l] == __[1]: + anticipating_nodes.add(__[1]) + break + else: + anticipating_nodes.add(stack[l]) + l -= 1 + if visited.count(__[1]) < 1: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return list(anticipating_nodes) + + def has_cycle(self): + stack = [] + visited = [] + s = list(self.graph.keys())[0] + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for __ in self.graph[s]: + if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: + l = len(stack) - 1 + while True and l >= 0: + if stack[l] == __[1]: + anticipating_nodes.add(__[1]) + break + else: + return True + anticipating_nodes.add(stack[l]) + l -= 1 + if visited.count(__[1]) < 1: + stack.append(__[1]) + visited.append(__[1]) + ss =__[1] + break + + # check if all the children are visited + if s == ss : + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return False + def all_nodes(self): + return list(self.graph) + + def dfs_time(self, s = -2, e = -1): + begin = time.time() + self.dfs(s,e) + end = time.time() + return end - begin + + def bfs_time(self, s = -2): + begin = time.time() + self.bfs(s) + end = time.time() + return end - begin diff --git a/Graphs/a_star.py b/Graphs/a_star.py new file mode 100644 index 000000000000..584222e6f62b --- /dev/null +++ b/Graphs/a_star.py @@ -0,0 +1,102 @@ +from __future__ import print_function + +grid = [[0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0],#0 are free path whereas 1's are obstacles + [0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 1, 0], + [0, 0, 0, 0, 1, 0]] + +''' +heuristic = [[9, 8, 7, 6, 5, 4], + [8, 7, 6, 5, 4, 3], + [7, 6, 5, 4, 3, 2], + [6, 5, 4, 3, 2, 1], + [5, 4, 3, 2, 1, 0]]''' + +init = [0, 0] +goal = [len(grid)-1, len(grid[0])-1] #all coordinates are given in format [y,x] +cost = 1 + +#the cost map which pushes the path closer to the goal +heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))] +for i in range(len(grid)): + for j in range(len(grid[0])): + heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1]) + if grid[i][j] == 1: + heuristic[i][j] = 99 #added extra penalty in the heuristic map + + +#the actions we can take +delta = [[-1, 0 ], # go up + [ 0, -1], # go left + [ 1, 0 ], # go down + [ 0, 1 ]] # go right + + +#function to search the path +def search(grid,init,goal,cost,heuristic): + + closed = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]# the referrence grid + closed[init[0]][init[1]] = 1 + action = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]#the action grid + + x = init[0] + y = init[1] + g = 0 + f = g + heuristic[init[0]][init[0]] + cell = [[f, g, x, y]] + + found = False # flag that is set when search is complete + resign = False # flag set if we can't find expand + + while not found and not resign: + if len(cell) == 0: + resign = True + return "FAIL" + else: + cell.sort()#to choose the least costliest action so as to move closer to the goal + cell.reverse() + next = cell.pop() + x = next[2] + y = next[3] + g = next[1] + f = next[0] + + + if x == goal[0] and y == goal[1]: + found = True + else: + for i in range(len(delta)):#to try out different valid actions + x2 = x + delta[i][0] + y2 = y + delta[i][1] + if x2 >= 0 and x2 < len(grid) and y2 >=0 and y2 < len(grid[0]): + if closed[x2][y2] == 0 and grid[x2][y2] == 0: + g2 = g + cost + f2 = g2 + heuristic[x2][y2] + cell.append([f2, g2, x2, y2]) + closed[x2][y2] = 1 + action[x2][y2] = i + invpath = [] + x = goal[0] + y = goal[1] + invpath.append([x, y])#we get the reverse path from here + while x != init[0] or y != init[1]: + x2 = x - delta[action[x][y]][0] + y2 = y - delta[action[x][y]][1] + x = x2 + y = y2 + invpath.append([x, y]) + + path = [] + for i in range(len(invpath)): + path.append(invpath[len(invpath) - 1 - i]) + print("ACTION MAP") + for i in range(len(action)): + print(action[i]) + + return path + +a = search(grid,init,goal,cost,heuristic) +for i in range(len(a)): + print(a[i]) + diff --git a/Graphs/articulation_points.py b/Graphs/articulation_points.py new file mode 100644 index 000000000000..1173c4ea373c --- /dev/null +++ b/Graphs/articulation_points.py @@ -0,0 +1,44 @@ +# Finding Articulation Points in Undirected Graph +def computeAP(l): + n = len(l) + outEdgeCount = 0 + low = [0] * n + visited = [False] * n + isArt = [False] * n + + def dfs(root, at, parent, outEdgeCount): + if parent == root: + outEdgeCount += 1 + visited[at] = True + low[at] = at + + for to in l[at]: + if to == parent: + pass + elif not visited[to]: + outEdgeCount = dfs(root, to, at, outEdgeCount) + low[at] = min(low[at], low[to]) + + # AP found via bridge + if at < low[to]: + isArt[at] = True + # AP found via cycle + if at == low[to]: + isArt[at] = True + else: + low[at] = min(low[at], to) + return outEdgeCount + + for i in range(n): + if not visited[i]: + outEdgeCount = 0 + outEdgeCount = dfs(i, i, -1, outEdgeCount) + isArt[i] = (outEdgeCount > 1) + + for x in range(len(isArt)): + if isArt[x] == True: + print(x) + +# Adjacency list of graph +l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]} +computeAP(l) diff --git a/Graphs/basic_graphs.py b/Graphs/basic_graphs.py new file mode 100644 index 000000000000..3b3abeb1720d --- /dev/null +++ b/Graphs/basic_graphs.py @@ -0,0 +1,290 @@ +from __future__ import print_function + +try: + raw_input # Python 2 +except NameError: + raw_input = input # Python 3 + +try: + xrange # Python 2 +except NameError: + xrange = range # Python 3 + +# Accept No. of Nodes and edges +n, m = map(int, raw_input().split(" ")) + +# Initialising Dictionary of edges +g = {} +for i in xrange(n): + g[i + 1] = [] + +""" +-------------------------------------------------------------------------------- + Accepting edges of Unweighted Directed Graphs +-------------------------------------------------------------------------------- +""" +for _ in xrange(m): + x, y = map(int, raw_input().split(" ")) + g[x].append(y) + +""" +-------------------------------------------------------------------------------- + Accepting edges of Unweighted Undirected Graphs +-------------------------------------------------------------------------------- +""" +for _ in xrange(m): + x, y = map(int, raw_input().split(" ")) + g[x].append(y) + g[y].append(x) + +""" +-------------------------------------------------------------------------------- + Accepting edges of Weighted Undirected Graphs +-------------------------------------------------------------------------------- +""" +for _ in xrange(m): + x, y, r = map(int, raw_input().split(" ")) + g[x].append([y, r]) + g[y].append([x, r]) + +""" +-------------------------------------------------------------------------------- + Depth First Search. + Args : G - Dictionary of edges + s - Starting Node + Vars : vis - Set of visited nodes + S - Traversal Stack +-------------------------------------------------------------------------------- +""" + + +def dfs(G, s): + vis, S = set([s]), [s] + print(s) + while S: + flag = 0 + for i in G[S[-1]]: + if i not in vis: + S.append(i) + vis.add(i) + flag = 1 + print(i) + break + if not flag: + S.pop() + + +""" +-------------------------------------------------------------------------------- + Breadth First Search. + Args : G - Dictionary of edges + s - Starting Node + Vars : vis - Set of visited nodes + Q - Traveral Stack +-------------------------------------------------------------------------------- +""" +from collections import deque + + +def bfs(G, s): + vis, Q = set([s]), deque([s]) + print(s) + while Q: + u = Q.popleft() + for v in G[u]: + if v not in vis: + vis.add(v) + Q.append(v) + print(v) + + +""" +-------------------------------------------------------------------------------- + Dijkstra's shortest path Algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to every other node + known - Set of knows nodes + path - Preceding node in path +-------------------------------------------------------------------------------- +""" + + +def dijk(G, s): + dist, known, path = {s: 0}, set(), {s: 0} + while True: + if len(known) == len(G) - 1: + break + mini = 100000 + for i in dist: + if i not in known and dist[i] < mini: + mini = dist[i] + u = i + known.add(u) + for v in G[u]: + if v[0] not in known: + if dist[u] + v[1] < dist.get(v[0], 100000): + dist[v[0]] = dist[u] + v[1] + path[v[0]] = u + for i in dist: + if i != s: + print(dist[i]) + + +""" +-------------------------------------------------------------------------------- + Topological Sort +-------------------------------------------------------------------------------- +""" +from collections import deque + + +def topo(G, ind=None, Q=[1]): + if ind is None: + ind = [0] * (len(G) + 1) # SInce oth Index is ignored + for u in G: + for v in G[u]: + ind[v] += 1 + Q = deque() + for i in G: + if ind[i] == 0: + Q.append(i) + if len(Q) == 0: + return + v = Q.popleft() + print(v) + for w in G[v]: + ind[w] -= 1 + if ind[w] == 0: + Q.append(w) + topo(G, ind, Q) + + +""" +-------------------------------------------------------------------------------- + Reading an Adjacency matrix +-------------------------------------------------------------------------------- +""" + + +def adjm(): + n, a = raw_input(), [] + for i in xrange(n): + a.append(map(int, raw_input().split())) + return a, n + + +""" +-------------------------------------------------------------------------------- + Floyd Warshall's algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to every other node + known - Set of knows nodes + path - Preceding node in path + +-------------------------------------------------------------------------------- +""" + + +def floy(A_and_n): + (A, n) = A_and_n + dist = list(A) + path = [[0] * n for i in xrange(n)] + for k in xrange(n): + for i in xrange(n): + for j in xrange(n): + if dist[i][j] > dist[i][k] + dist[k][j]: + dist[i][j] = dist[i][k] + dist[k][j] + path[i][k] = k + print(dist) + + +""" +-------------------------------------------------------------------------------- + Prim's MST Algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to nearest node + known - Set of knows nodes + path - Preceding node in path +-------------------------------------------------------------------------------- +""" + + +def prim(G, s): + dist, known, path = {s: 0}, set(), {s: 0} + while True: + if len(known) == len(G) - 1: + break + mini = 100000 + for i in dist: + if i not in known and dist[i] < mini: + mini = dist[i] + u = i + known.add(u) + for v in G[u]: + if v[0] not in known: + if v[1] < dist.get(v[0], 100000): + dist[v[0]] = v[1] + path[v[0]] = u + + +""" +-------------------------------------------------------------------------------- + Accepting Edge list + Vars : n - Number of nodes + m - Number of edges + Returns : l - Edge list + n - Number of Nodes +-------------------------------------------------------------------------------- +""" + + +def edglist(): + n, m = map(int, raw_input().split(" ")) + l = [] + for i in xrange(m): + l.append(map(int, raw_input().split(' '))) + return l, n + + +""" +-------------------------------------------------------------------------------- + Kruskal's MST Algorithm + Args : E - Edge list + n - Number of Nodes + Vars : s - Set of all nodes as unique disjoint sets (initially) +-------------------------------------------------------------------------------- +""" + + +def krusk(E_and_n): + # Sort edges on the basis of distance + (E, n) = E_and_n + E.sort(reverse=True, key=lambda x: x[2]) + s = [set([i]) for i in range(1, n + 1)] + while True: + if len(s) == 1: + break + print(s) + x = E.pop() + for i in xrange(len(s)): + if x[0] in s[i]: + break + for j in xrange(len(s)): + if x[1] in s[j]: + if i == j: + break + s[j].update(s[i]) + s.pop(i) + break + + +# find the isolated node in the graph +def find_isolated_nodes(graph): + isolated = [] + for node in graph: + if not graph[node]: + isolated.append(node) + return isolated diff --git a/Graphs/bellman_ford.py b/Graphs/bellman_ford.py new file mode 100644 index 000000000000..82db80546b94 --- /dev/null +++ b/Graphs/bellman_ford.py @@ -0,0 +1,54 @@ +from __future__ import print_function + +def printDist(dist, V): + print("\nVertex Distance") + for i in range(V): + if dist[i] != float('inf') : + print(i,"\t",int(dist[i]),end = "\t") + else: + print(i,"\t","INF",end="\t") + print() + +def BellmanFord(graph, V, E, src): + mdist=[float('inf') for i in range(V)] + mdist[src] = 0.0 + + for i in range(V-1): + for j in range(V): + u = graph[j]["src"] + v = graph[j]["dst"] + w = graph[j]["weight"] + + if mdist[u] != float('inf') and mdist[u] + w < mdist[v]: + mdist[v] = mdist[u] + w + for j in range(V): + u = graph[j]["src"] + v = graph[j]["dst"] + w = graph[j]["weight"] + + if mdist[u] != float('inf') and mdist[u] + w < mdist[v]: + print("Negative cycle found. Solution not possible.") + return + + printDist(mdist, V) + + + +#MAIN +V = int(input("Enter number of vertices: ")) +E = int(input("Enter number of edges: ")) + +graph = [dict() for j in range(E)] + +for i in range(V): + graph[i][i] = 0.0 + +for i in range(E): + print("\nEdge ",i+1) + src = int(input("Enter source:")) + dst = int(input("Enter destination:")) + weight = float(input("Enter weight:")) + graph[i] = {"src": src,"dst": dst, "weight": weight} + +gsrc = int(input("\nEnter shortest path source:")) +BellmanFord(graph, V, E, gsrc) diff --git a/Graphs/breadth_first_search.py b/Graphs/breadth_first_search.py new file mode 100644 index 000000000000..3992e2d4d892 --- /dev/null +++ b/Graphs/breadth_first_search.py @@ -0,0 +1,67 @@ +#!/usr/bin/python +# encoding=utf8 + +""" Author: OMKAR PATHAK """ + +from __future__ import print_function + + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def BFS(self, startVertex): + # Take a list for stoting already visited vertexes + visited = [False] * len(self.vertex) + + # create a list to store all the vertexes for BFS + queue = [] + + # mark the source node as visited and enqueue it + visited[startVertex] = True + queue.append(startVertex) + + while queue: + startVertex = queue.pop(0) + print(startVertex, end = ' ') + + # mark all adjacent nodes as visited and print them + for i in self.vertex[startVertex]: + if visited[i] == False: + queue.append(i) + visited[i] = True + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('BFS:') + g.BFS(2) + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # BFS: + # 2 0 3 1 diff --git a/Graphs/check_bipartite_graph_bfs.py b/Graphs/check_bipartite_graph_bfs.py new file mode 100644 index 000000000000..1b9c32c6ccc4 --- /dev/null +++ b/Graphs/check_bipartite_graph_bfs.py @@ -0,0 +1,43 @@ +# Check whether Graph is Bipartite or Not using BFS + +# A Bipartite Graph is a graph whose vertices can be divided into two independent sets, +# U and V such that every edge (u, v) either connects a vertex from U to V or a vertex +# from V to U. In other words, for every edge (u, v), either u belongs to U and v to V, +# or u belongs to V and v to U. We can also say that there is no edge that connects +# vertices of same set. +def checkBipartite(l): + queue = [] + visited = [False] * len(l) + color = [-1] * len(l) + + def bfs(): + while(queue): + u = queue.pop(0) + visited[u] = True + + for neighbour in l[u]: + + if neighbour == u: + return False + + if color[neighbour] == -1: + color[neighbour] = 1 - color[u] + queue.append(neighbour) + + elif color[neighbour] == color[u]: + return False + + return True + + for i in range(len(l)): + if not visited[i]: + queue.append(i) + color[i] = 0 + if bfs() == False: + return False + + return True + +# Adjacency List of graph +l = {0:[1,3], 1:[0,2], 2:[1,3], 3:[0,2]} +print(checkBipartite(l)) diff --git a/Graphs/depth_first_search.py b/Graphs/depth_first_search.py new file mode 100644 index 000000000000..98faf61354f9 --- /dev/null +++ b/Graphs/depth_first_search.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +# encoding=utf8 + +""" Author: OMKAR PATHAK """ +from __future__ import print_function + + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + print(self.vertex) + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def DFS(self): + # visited array for storing already visited nodes + visited = [False] * len(self.vertex) + + # call the recursive helper function + for i in range(len(self.vertex)): + if visited[i] == False: + self.DFSRec(i, visited) + + def DFSRec(self, startVertex, visited): + # mark start vertex as visited + visited[startVertex] = True + + print(startVertex, end = ' ') + + # Recur for all the vertexes that are adjacent to this node + for i in self.vertex.keys(): + if visited[i] == False: + self.DFSRec(i, visited) + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('DFS:') + g.DFS() + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # DFS: + # 0 1 2 3 diff --git a/Graphs/dijkstra.py b/Graphs/dijkstra.py new file mode 100644 index 000000000000..6b08b28fcfd3 --- /dev/null +++ b/Graphs/dijkstra.py @@ -0,0 +1,47 @@ +"""pseudo-code""" + +""" +DIJKSTRA(graph G, start vertex s,destination vertex d): +// all nodes initially unexplored +let H = min heap data structure, initialized with 0 and s [here 0 indicates the distance from start vertex] +while H is non-empty: + remove the first node and cost of H, call it U and cost + if U is not explored + mark U as explored + if U is d: + return cost // total cost from start to destination vertex + for each edge(U, V): c=cost of edge(u,V) // for V in graph[U] + if V unexplored: + next=cost+c + add next,V to H (at the end) +""" +import heapq + + +def dijkstra(graph, start, end): + heap = [(0, start)] # cost from start node,end node + visited = [] + while heap: + (cost, u) = heapq.heappop(heap) + if u in visited: + continue + visited.append(u) + if u == end: + return cost + for v, c in G[u]: + if v in visited: + continue + next = cost + c + heapq.heappush(heap, (next, v)) + return (-1, -1) + + +G = {'A': [['B', 2], ['C', 5]], + 'B': [['A', 2], ['D', 3], ['E', 1]], + 'C': [['A', 5], ['F', 3]], + 'D': [['B', 3]], + 'E': [['B', 1], ['F', 3]], + 'F': [['C', 3], ['E', 3]]} + +shortDistance = dijkstra(G, 'E', 'C') +print(shortDistance) diff --git a/Graphs/dijkstra_2.py b/Graphs/dijkstra_2.py new file mode 100644 index 000000000000..a6c340e8a68d --- /dev/null +++ b/Graphs/dijkstra_2.py @@ -0,0 +1,57 @@ +from __future__ import print_function + +def printDist(dist, V): + print("\nVertex Distance") + for i in range(V): + if dist[i] != float('inf') : + print(i,"\t",int(dist[i]),end = "\t") + else: + print(i,"\t","INF",end="\t") + print() + +def minDist(mdist, vset, V): + minVal = float('inf') + minInd = -1 + for i in range(V): + if (not vset[i]) and mdist[i] < minVal : + minInd = i + minVal = mdist[i] + return minInd + +def Dijkstra(graph, V, src): + mdist=[float('inf') for i in range(V)] + vset = [False for i in range(V)] + mdist[src] = 0.0 + + for i in range(V-1): + u = minDist(mdist, vset, V) + vset[u] = True + + for v in range(V): + if (not vset[v]) and graph[u][v]!=float('inf') and mdist[u] + graph[u][v] < mdist[v]: + mdist[v] = mdist[u] + graph[u][v] + + + + printDist(mdist, V) + + + +#MAIN +V = int(input("Enter number of vertices: ")) +E = int(input("Enter number of edges: ")) + +graph = [[float('inf') for i in range(V)] for j in range(V)] + +for i in range(V): + graph[i][i] = 0.0 + +for i in range(E): + print("\nEdge ",i+1) + src = int(input("Enter source:")) + dst = int(input("Enter destination:")) + weight = float(input("Enter weight:")) + graph[src][dst] = weight + +gsrc = int(input("\nEnter shortest path source:")) +Dijkstra(graph, V, gsrc) diff --git a/Graphs/dijkstra_algorithm.py b/Graphs/dijkstra_algorithm.py new file mode 100644 index 000000000000..985c7f6c1301 --- /dev/null +++ b/Graphs/dijkstra_algorithm.py @@ -0,0 +1,212 @@ +# Title: Dijkstra's Algorithm for finding single source shortest path from scratch +# Author: Shubham Malik +# References: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + +from __future__ import print_function +import math +import sys +# For storing the vertex set to retreive node with the lowest distance + + +class PriorityQueue: + # Based on Min Heap + def __init__(self): + self.cur_size = 0 + self.array = [] + self.pos = {} # To store the pos of node in array + + def isEmpty(self): + return self.cur_size == 0 + + def min_heapify(self, idx): + lc = self.left(idx) + rc = self.right(idx) + if lc < self.cur_size and self.array(lc)[0] < self.array(idx)[0]: + smallest = lc + else: + smallest = idx + if rc < self.cur_size and self.array(rc)[0] < self.array(smallest)[0]: + smallest = rc + if smallest != idx: + self.swap(idx, smallest) + self.min_heapify(smallest) + + def insert(self, tup): + # Inserts a node into the Priority Queue + self.pos[tup[1]] = self.cur_size + self.cur_size += 1 + self.array.append((sys.maxsize, tup[1])) + self.decrease_key((sys.maxsize, tup[1]), tup[0]) + + def extract_min(self): + # Removes and returns the min element at top of priority queue + min_node = self.array[0][1] + self.array[0] = self.array[self.cur_size - 1] + self.cur_size -= 1 + self.min_heapify(1) + del self.pos[min_node] + return min_node + + def left(self, i): + # returns the index of left child + return 2 * i + 1 + + def right(self, i): + # returns the index of right child + return 2 * i + 2 + + def par(self, i): + # returns the index of parent + return math.floor(i / 2) + + def swap(self, i, j): + # swaps array elements at indices i and j + # update the pos{} + self.pos[self.array[i][1]] = j + self.pos[self.array[j][1]] = i + temp = self.array[i] + self.array[i] = self.array[j] + self.array[j] = temp + + def decrease_key(self, tup, new_d): + idx = self.pos[tup[1]] + # assuming the new_d is atmost old_d + self.array[idx] = (new_d, tup[1]) + while idx > 0 and self.array[self.par(idx)][0] > self.array[idx][0]: + self.swap(idx, self.par(idx)) + idx = self.par(idx) + + +class Graph: + def __init__(self, num): + self.adjList = {} # To store graph: u -> (v,w) + self.num_nodes = num # Number of nodes in graph + # To store the distance from source vertex + self.dist = [0] * self.num_nodes + self.par = [-1] * self.num_nodes # To store the path + + def add_edge(self, u, v, w): + # Edge going from node u to v and v to u with weight w + # u (w)-> v, v (w) -> u + # Check if u already in graph + if u in self.adjList.keys(): + self.adjList[u].append((v, w)) + else: + self.adjList[u] = [(v, w)] + + # Assuming undirected graph + if v in self.adjList.keys(): + self.adjList[v].append((u, w)) + else: + self.adjList[v] = [(u, w)] + + def show_graph(self): + # u -> v(w) + for u in self.adjList: + print(u, '->', ' -> '.join(str("{}({})".format(v, w)) + for v, w in self.adjList[u])) + + def dijkstra(self, src): + # Flush old junk values in par[] + self.par = [-1] * self.num_nodes + # src is the source node + self.dist[src] = 0 + Q = PriorityQueue() + Q.insert((0, src)) # (dist from src, node) + for u in self.adjList.keys(): + if u != src: + self.dist[u] = sys.maxsize # Infinity + self.par[u] = -1 + + while not Q.isEmpty(): + u = Q.extract_min() # Returns node with the min dist from source + # Update the distance of all the neighbours of u and + # if their prev dist was INFINITY then push them in Q + for v, w in self.adjList[u]: + new_dist = self.dist[u] + w + if self.dist[v] > new_dist: + if self.dist[v] == sys.maxsize: + Q.insert((new_dist, v)) + else: + Q.decrease_key((self.dist[v], v), new_dist) + self.dist[v] = new_dist + self.par[v] = u + + # Show the shortest distances from src + self.show_distances(src) + + def show_distances(self, src): + print("Distance from node: {}".format(src)) + for u in range(self.num_nodes): + print('Node {} has distance: {}'.format(u, self.dist[u])) + + def show_path(self, src, dest): + # To show the shortest path from src to dest + # WARNING: Use it *after* calling dijkstra + path = [] + cost = 0 + temp = dest + # Backtracking from dest to src + while self.par[temp] != -1: + path.append(temp) + if temp != src: + for v, w in self.adjList[temp]: + if v == self.par[temp]: + cost += w + break + temp = self.par[temp] + path.append(src) + path.reverse() + + print('----Path to reach {} from {}----'.format(dest, src)) + for u in path: + print('{}'.format(u), end=' ') + if u != dest: + print('-> ', end='') + + print('\nTotal cost of path: ', cost) + + +if __name__ == '__main__': + graph = Graph(9) + graph.add_edge(0, 1, 4) + graph.add_edge(0, 7, 8) + graph.add_edge(1, 2, 8) + graph.add_edge(1, 7, 11) + graph.add_edge(2, 3, 7) + graph.add_edge(2, 8, 2) + graph.add_edge(2, 5, 4) + graph.add_edge(3, 4, 9) + graph.add_edge(3, 5, 14) + graph.add_edge(4, 5, 10) + graph.add_edge(5, 6, 2) + graph.add_edge(6, 7, 1) + graph.add_edge(6, 8, 6) + graph.add_edge(7, 8, 7) + graph.show_graph() + graph.dijkstra(0) + graph.show_path(0, 4) + +# OUTPUT +# 0 -> 1(4) -> 7(8) +# 1 -> 0(4) -> 2(8) -> 7(11) +# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7) +# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4) +# 3 -> 2(7) -> 4(9) -> 5(14) +# 8 -> 2(2) -> 6(6) -> 7(7) +# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2) +# 4 -> 3(9) -> 5(10) +# 6 -> 5(2) -> 7(1) -> 8(6) +# Distance from node: 0 +# Node 0 has distance: 0 +# Node 1 has distance: 4 +# Node 2 has distance: 12 +# Node 3 has distance: 19 +# Node 4 has distance: 21 +# Node 5 has distance: 11 +# Node 6 has distance: 9 +# Node 7 has distance: 8 +# Node 8 has distance: 14 +# ----Path to reach 4 from 0---- +# 0 -> 7 -> 6 -> 5 -> 4 +# Total cost of path: 21 diff --git a/Graphs/even_tree.py b/Graphs/even_tree.py new file mode 100644 index 000000000000..9383ea9a13c1 --- /dev/null +++ b/Graphs/even_tree.py @@ -0,0 +1,70 @@ +""" +You are given a tree(a simple connected graph with no cycles). The tree has N +nodes numbered from 1 to N and is rooted at node 1. + +Find the maximum number of edges you can remove from the tree to get a forest +such that each connected component of the forest contains an even number of +nodes. + +Constraints +2 <= 2 <= 100 + +Note: The tree input will be such that it can always be decomposed into +components containing an even number of nodes. +""" +from __future__ import print_function +# pylint: disable=invalid-name +from collections import defaultdict + + +def dfs(start): + """DFS traversal""" + # pylint: disable=redefined-outer-name + ret = 1 + visited[start] = True + for v in tree.get(start): + if v not in visited: + ret += dfs(v) + if ret % 2 == 0: + cuts.append(start) + return ret + + +def even_tree(): + """ + 2 1 + 3 1 + 4 3 + 5 2 + 6 1 + 7 2 + 8 6 + 9 8 + 10 8 + On removing edges (1,3) and (1,6), we can get the desired result 2. + """ + dfs(1) + + +if __name__ == '__main__': + n, m = 10, 9 + tree = defaultdict(list) + visited = {} + cuts = [] + count = 0 + edges = [ + (2, 1), + (3, 1), + (4, 3), + (5, 2), + (6, 1), + (7, 2), + (8, 6), + (9, 8), + (10, 8), + ] + for u, v in edges: + tree[u].append(v) + tree[v].append(u) + even_tree() + print(len(cuts) - 1) diff --git a/Graphs/finding_bridges.py b/Graphs/finding_bridges.py new file mode 100644 index 000000000000..56533dd48bde --- /dev/null +++ b/Graphs/finding_bridges.py @@ -0,0 +1,31 @@ +# Finding Bridges in Undirected Graph +def computeBridges(l): + id = 0 + n = len(l) # No of vertices in graph + low = [0] * n + visited = [False] * n + + def dfs(at, parent, bridges, id): + visited[at] = True + low[at] = id + id += 1 + for to in l[at]: + if to == parent: + pass + elif not visited[to]: + dfs(to, at, bridges, id) + low[at] = min(low[at], low[to]) + if at < low[to]: + bridges.append([at, to]) + else: + # This edge is a back edge and cannot be a bridge + low[at] = min(low[at], to) + + bridges = [] + for i in range(n): + if (not visited[i]): + dfs(i, -1, bridges, id) + print(bridges) + +l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]} +computeBridges(l) diff --git a/Graphs/floyd_warshall.py b/Graphs/floyd_warshall.py new file mode 100644 index 000000000000..fae8b19b351a --- /dev/null +++ b/Graphs/floyd_warshall.py @@ -0,0 +1,48 @@ +from __future__ import print_function + +def printDist(dist, V): + print("\nThe shortest path matrix using Floyd Warshall algorithm\n") + for i in range(V): + for j in range(V): + if dist[i][j] != float('inf') : + print(int(dist[i][j]),end = "\t") + else: + print("INF",end="\t") + print() + + + +def FloydWarshall(graph, V): + dist=[[float('inf') for i in range(V)] for j in range(V)] + + for i in range(V): + for j in range(V): + dist[i][j] = graph[i][j] + + for k in range(V): + for i in range(V): + for j in range(V): + if dist[i][k]!=float('inf') and dist[k][j]!=float('inf') and dist[i][k]+dist[k][j] < dist[i][j]: + dist[i][j] = dist[i][k] + dist[k][j] + + printDist(dist, V) + + + +#MAIN +V = int(input("Enter number of vertices: ")) +E = int(input("Enter number of edges: ")) + +graph = [[float('inf') for i in range(V)] for j in range(V)] + +for i in range(V): + graph[i][i] = 0.0 + +for i in range(E): + print("\nEdge ",i+1) + src = int(input("Enter source:")) + dst = int(input("Enter destination:")) + weight = float(input("Enter weight:")) + graph[src][dst] = weight + +FloydWarshall(graph, V) diff --git a/Graphs/graph.py b/Graphs/graph.py new file mode 100644 index 000000000000..9bd61559dcbf --- /dev/null +++ b/Graphs/graph.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# encoding=utf8 + +from __future__ import print_function +# Author: OMKAR PATHAK + +# We can use Python's dictionary for constructing the graph + +class AdjacencyList(object): + def __init__(self): + self.List = {} + + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present + if fromVertex in self.List.keys(): + self.List[fromVertex].append(toVertex) + else: + self.List[fromVertex] = [toVertex] + + def printList(self): + for i in self.List: + print((i,'->',' -> '.join([str(j) for j in self.List[i]]))) + +if __name__ == '__main__': + al = AdjacencyList() + al.addEdge(0, 1) + al.addEdge(0, 4) + al.addEdge(4, 1) + al.addEdge(4, 3) + al.addEdge(1, 0) + al.addEdge(1, 4) + al.addEdge(1, 3) + al.addEdge(1, 2) + al.addEdge(2, 3) + al.addEdge(3, 4) + + al.printList() + + # OUTPUT: + # 0 -> 1 -> 4 + # 1 -> 0 -> 4 -> 3 -> 2 + # 2 -> 3 + # 3 -> 4 + # 4 -> 1 -> 3 diff --git a/Graphs/graph_list.py b/Graphs/graph_list.py new file mode 100644 index 000000000000..d67bc96c4a81 --- /dev/null +++ b/Graphs/graph_list.py @@ -0,0 +1,31 @@ +from __future__ import print_function + + +class Graph: + def __init__(self, vertex): + self.vertex = vertex + self.graph = [[0] for i in range(vertex)] + + def add_edge(self, u, v): + self.graph[u - 1].append(v - 1) + + def show(self): + for i in range(self.vertex): + print('%d: '% (i + 1), end=' ') + for j in self.graph[i]: + print('%d-> '% (j + 1), end=' ') + print(' ') + + + +g = Graph(100) + +g.add_edge(1,3) +g.add_edge(2,3) +g.add_edge(3,4) +g.add_edge(3,5) +g.add_edge(4,5) + + +g.show() + diff --git a/Graphs/graph_matrix.py b/Graphs/graph_matrix.py new file mode 100644 index 000000000000..de25301d6dd1 --- /dev/null +++ b/Graphs/graph_matrix.py @@ -0,0 +1,32 @@ +from __future__ import print_function + + +class Graph: + + def __init__(self, vertex): + self.vertex = vertex + self.graph = [[0] * vertex for i in range(vertex) ] + + def add_edge(self, u, v): + self.graph[u - 1][v - 1] = 1 + self.graph[v - 1][u - 1] = 1 + + def show(self): + + for i in self.graph: + for j in i: + print(j, end=' ') + print(' ') + + + + +g = Graph(100) + +g.add_edge(1,4) +g.add_edge(4,2) +g.add_edge(4,5) +g.add_edge(2,5) +g.add_edge(5,3) +g.show() + diff --git a/Graphs/kahns_algorithm_long.py b/Graphs/kahns_algorithm_long.py new file mode 100644 index 000000000000..453b5706f6da --- /dev/null +++ b/Graphs/kahns_algorithm_long.py @@ -0,0 +1,30 @@ +# Finding longest distance in Directed Acyclic Graph using KahnsAlgorithm +def longestDistance(l): + indegree = [0] * len(l) + queue = [] + longDist = [1] * len(l) + + for key, values in l.items(): + for i in values: + indegree[i] += 1 + + for i in range(len(indegree)): + if indegree[i] == 0: + queue.append(i) + + while(queue): + vertex = queue.pop(0) + for x in l[vertex]: + indegree[x] -= 1 + + if longDist[vertex] + 1 > longDist[x]: + longDist[x] = longDist[vertex] + 1 + + if indegree[x] == 0: + queue.append(x) + + print(max(longDist)) + +# Adjacency list of Graph +l = {0:[2,3,4], 1:[2,7], 2:[5], 3:[5,7], 4:[7], 5:[6], 6:[7], 7:[]} +longestDistance(l) diff --git a/Graphs/kahns_algorithm_topo.py b/Graphs/kahns_algorithm_topo.py new file mode 100644 index 000000000000..8c182c4e902c --- /dev/null +++ b/Graphs/kahns_algorithm_topo.py @@ -0,0 +1,32 @@ +# Kahn's Algorithm is used to find Topological ordering of Directed Acyclic Graph using BFS +def topologicalSort(l): + indegree = [0] * len(l) + queue = [] + topo = [] + cnt = 0 + + for key, values in l.items(): + for i in values: + indegree[i] += 1 + + for i in range(len(indegree)): + if indegree[i] == 0: + queue.append(i) + + while(queue): + vertex = queue.pop(0) + cnt += 1 + topo.append(vertex) + for x in l[vertex]: + indegree[x] -= 1 + if indegree[x] == 0: + queue.append(x) + + if cnt != len(l): + print("Cycle exists") + else: + print(topo) + +# Adjacency List of Graph +l = {0:[1,2], 1:[3], 2:[3], 3:[4,5], 4:[], 5:[]} +topologicalSort(l) diff --git a/Graphs/minimum_spanning_tree_kruskal.py b/Graphs/minimum_spanning_tree_kruskal.py new file mode 100644 index 000000000000..81d64f421a31 --- /dev/null +++ b/Graphs/minimum_spanning_tree_kruskal.py @@ -0,0 +1,32 @@ +from __future__ import print_function +num_nodes, num_edges = list(map(int,input().split())) + +edges = [] + +for i in range(num_edges): + node1, node2, cost = list(map(int,input().split())) + edges.append((i,node1,node2,cost)) + +edges = sorted(edges, key=lambda edge: edge[3]) + +parent = [i for i in range(num_nodes)] + +def find_parent(i): + if(i != parent[i]): + parent[i] = find_parent(parent[i]) + return parent[i] + +minimum_spanning_tree_cost = 0 +minimum_spanning_tree = [] + +for edge in edges: + parent_a = find_parent(edge[1]) + parent_b = find_parent(edge[2]) + if(parent_a != parent_b): + minimum_spanning_tree_cost += edge[3] + minimum_spanning_tree.append(edge) + parent[parent_a] = parent_b + +print(minimum_spanning_tree_cost) +for edge in minimum_spanning_tree: + print(edge) diff --git a/Graphs/minimum_spanning_tree_prims.py b/Graphs/minimum_spanning_tree_prims.py new file mode 100644 index 000000000000..7b1ad0e743f7 --- /dev/null +++ b/Graphs/minimum_spanning_tree_prims.py @@ -0,0 +1,111 @@ +import sys +from collections import defaultdict + +def PrimsAlgorithm(l): + + nodePosition = [] + def getPosition(vertex): + return nodePosition[vertex] + + def setPosition(vertex, pos): + nodePosition[vertex] = pos + + def topToBottom(heap, start, size, positions): + if start > size // 2 - 1: + return + else: + if 2 * start + 2 >= size: + m = 2 * start + 1 + else: + if heap[2 * start + 1] < heap[2 * start + 2]: + m = 2 * start + 1 + else: + m = 2 * start + 2 + if heap[m] < heap[start]: + temp, temp1 = heap[m], positions[m] + heap[m], positions[m] = heap[start], positions[start] + heap[start], positions[start] = temp, temp1 + + temp = getPosition(positions[m]) + setPosition(positions[m], getPosition(positions[start])) + setPosition(positions[start], temp) + + topToBottom(heap, m, size, positions) + + # Update function if value of any node in min-heap decreases + def bottomToTop(val, index, heap, position): + temp = position[index] + + while(index != 0): + if index % 2 == 0: + parent = int( (index-2) / 2 ) + else: + parent = int( (index-1) / 2 ) + + if val < heap[parent]: + heap[index] = heap[parent] + position[index] = position[parent] + setPosition(position[parent], index) + else: + heap[index] = val + position[index] = temp + setPosition(temp, index) + break + index = parent + else: + heap[0] = val + position[0] = temp + setPosition(temp, 0) + + def heapify(heap, positions): + start = len(heap) // 2 - 1 + for i in range(start, -1, -1): + topToBottom(heap, i, len(heap), positions) + + def deleteMinimum(heap, positions): + temp = positions[0] + heap[0] = sys.maxsize + topToBottom(heap, 0, len(heap), positions) + return temp + + visited = [0 for i in range(len(l))] + Nbr_TV = [-1 for i in range(len(l))] # Neighboring Tree Vertex of selected vertex + # Minimum Distance of explored vertex with neighboring vertex of partial tree formed in graph + Distance_TV = [] # Heap of Distance of vertices from their neighboring vertex + Positions = [] + + for x in range(len(l)): + p = sys.maxsize + Distance_TV.append(p) + Positions.append(x) + nodePosition.append(x) + + TreeEdges = [] + visited[0] = 1 + Distance_TV[0] = sys.maxsize + for x in l[0]: + Nbr_TV[ x[0] ] = 0 + Distance_TV[ x[0] ] = x[1] + heapify(Distance_TV, Positions) + + for i in range(1, len(l)): + vertex = deleteMinimum(Distance_TV, Positions) + if visited[vertex] == 0: + TreeEdges.append((Nbr_TV[vertex], vertex)) + visited[vertex] = 1 + for v in l[vertex]: + if visited[v[0]] == 0 and v[1] < Distance_TV[ getPosition(v[0]) ]: + Distance_TV[ getPosition(v[0]) ] = v[1] + bottomToTop(v[1], getPosition(v[0]), Distance_TV, Positions) + Nbr_TV[ v[0] ] = vertex + return TreeEdges + +# < --------- Prims Algorithm --------- > +n = int(input("Enter number of vertices: ")) +e = int(input("Enter number of edges: ")) +adjlist = defaultdict(list) +for x in range(e): + l = [int(x) for x in input().split()] + adjlist[l[0]].append([ l[1], l[2] ]) + adjlist[l[1]].append([ l[0], l[2] ]) +print(PrimsAlgorithm(adjlist)) diff --git a/Graphs/multi_hueristic_astar.py b/Graphs/multi_hueristic_astar.py new file mode 100644 index 000000000000..1acd098f327d --- /dev/null +++ b/Graphs/multi_hueristic_astar.py @@ -0,0 +1,266 @@ +from __future__ import print_function +import heapq +import numpy as np + +try: + xrange # Python 2 +except NameError: + xrange = range # Python 3 + + +class PriorityQueue: + def __init__(self): + self.elements = [] + self.set = set() + + def minkey(self): + if not self.empty(): + return self.elements[0][0] + else: + return float('inf') + + def empty(self): + return len(self.elements) == 0 + + def put(self, item, priority): + if item not in self.set: + heapq.heappush(self.elements, (priority, item)) + self.set.add(item) + else: + # update + # print("update", item) + temp = [] + (pri, x) = heapq.heappop(self.elements) + while x != item: + temp.append((pri, x)) + (pri, x) = heapq.heappop(self.elements) + temp.append((priority, item)) + for (pro, xxx) in temp: + heapq.heappush(self.elements, (pro, xxx)) + + def remove_element(self, item): + if item in self.set: + self.set.remove(item) + temp = [] + (pro, x) = heapq.heappop(self.elements) + while x != item: + temp.append((pro, x)) + (pro, x) = heapq.heappop(self.elements) + for (prito, yyy) in temp: + heapq.heappush(self.elements, (prito, yyy)) + + def top_show(self): + return self.elements[0][1] + + def get(self): + (priority, item) = heapq.heappop(self.elements) + self.set.remove(item) + return (priority, item) + +def consistent_hueristic(P, goal): + # euclidean distance + a = np.array(P) + b = np.array(goal) + return np.linalg.norm(a - b) + +def hueristic_2(P, goal): + # integer division by time variable + return consistent_hueristic(P, goal) // t + +def hueristic_1(P, goal): + # manhattan distance + return abs(P[0] - goal[0]) + abs(P[1] - goal[1]) + +def key(start, i, goal, g_function): + ans = g_function[start] + W1 * hueristics[i](start, goal) + return ans + +def do_something(back_pointer, goal, start): + grid = np.chararray((n, n)) + for i in range(n): + for j in range(n): + grid[i][j] = '*' + + for i in range(n): + for j in range(n): + if (j, (n-1)-i) in blocks: + grid[i][j] = "#" + + grid[0][(n-1)] = "-" + x = back_pointer[goal] + while x != start: + (x_c, y_c) = x + # print(x) + grid[(n-1)-y_c][x_c] = "-" + x = back_pointer[x] + grid[(n-1)][0] = "-" + + + for i in xrange(n): + for j in range(n): + if (i, j) == (0, n-1): + print(grid[i][j], end=' ') + print("<-- End position", end=' ') + else: + print(grid[i][j], end=' ') + print() + print("^") + print("Start position") + print() + print("# is an obstacle") + print("- is the path taken by algorithm") + print("PATH TAKEN BY THE ALGORITHM IS:-") + x = back_pointer[goal] + while x != start: + print(x, end=' ') + x = back_pointer[x] + print(x) + quit() + +def valid(p): + if p[0] < 0 or p[0] > n-1: + return False + if p[1] < 0 or p[1] > n-1: + return False + return True + +def expand_state(s, j, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer): + for itera in range(n_hueristic): + open_list[itera].remove_element(s) + # print("s", s) + # print("j", j) + (x, y) = s + left = (x-1, y) + right = (x+1, y) + up = (x, y+1) + down = (x, y-1) + + for neighbours in [left, right, up, down]: + if neighbours not in blocks: + if valid(neighbours) and neighbours not in visited: + # print("neighbour", neighbours) + visited.add(neighbours) + back_pointer[neighbours] = -1 + g_function[neighbours] = float('inf') + + if valid(neighbours) and g_function[neighbours] > g_function[s] + 1: + g_function[neighbours] = g_function[s] + 1 + back_pointer[neighbours] = s + if neighbours not in close_list_anchor: + open_list[0].put(neighbours, key(neighbours, 0, goal, g_function)) + if neighbours not in close_list_inad: + for var in range(1,n_hueristic): + if key(neighbours, var, goal, g_function) <= W2 * key(neighbours, 0, goal, g_function): + # print("why not plssssssssss") + open_list[j].put(neighbours, key(neighbours, var, goal, g_function)) + + + # print + +def make_common_ground(): + some_list = [] + # block 1 + for x in range(1, 5): + for y in range(1, 6): + some_list.append((x, y)) + + # line + for x in range(15, 20): + some_list.append((x, 17)) + + # block 2 big + for x in range(10, 19): + for y in range(1, 15): + some_list.append((x, y)) + + # L block + for x in range(1, 4): + for y in range(12, 19): + some_list.append((x, y)) + for x in range(3, 13): + for y in range(16, 19): + some_list.append((x, y)) + return some_list + +hueristics = {0: consistent_hueristic, 1: hueristic_1, 2: hueristic_2} + +blocks_blk = [(0, 1),(1, 1),(2, 1),(3, 1),(4, 1),(5, 1),(6, 1),(7, 1),(8, 1),(9, 1),(10, 1),(11, 1),(12, 1),(13, 1),(14, 1),(15, 1),(16, 1),(17, 1),(18, 1), (19, 1)] +blocks_no = [] +blocks_all = make_common_ground() + + + + +blocks = blocks_blk +# hyper parameters +W1 = 1 +W2 = 1 +n = 20 +n_hueristic = 3 # one consistent and two other inconsistent + +# start and end destination +start = (0, 0) +goal = (n-1, n-1) + +t = 1 +def multi_a_star(start, goal, n_hueristic): + g_function = {start: 0, goal: float('inf')} + back_pointer = {start:-1, goal:-1} + open_list = [] + visited = set() + + for i in range(n_hueristic): + open_list.append(PriorityQueue()) + open_list[i].put(start, key(start, i, goal, g_function)) + + close_list_anchor = [] + close_list_inad = [] + while open_list[0].minkey() < float('inf'): + for i in range(1, n_hueristic): + # print("i", i) + # print(open_list[0].minkey(), open_list[i].minkey()) + if open_list[i].minkey() <= W2 * open_list[0].minkey(): + global t + t += 1 + # print("less prio") + if g_function[goal] <= open_list[i].minkey(): + if g_function[goal] < float('inf'): + do_something(back_pointer, goal, start) + else: + _, get_s = open_list[i].top_show() + visited.add(get_s) + expand_state(get_s, i, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer) + close_list_inad.append(get_s) + else: + # print("more prio") + if g_function[goal] <= open_list[0].minkey(): + if g_function[goal] < float('inf'): + do_something(back_pointer, goal, start) + else: + # print("hoolla") + get_s = open_list[0].top_show() + visited.add(get_s) + expand_state(get_s, 0, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer) + close_list_anchor.append(get_s) + print("No path found to goal") + print() + for i in range(n-1,-1, -1): + for j in range(n): + if (j, i) in blocks: + print('#', end=' ') + elif (j, i) in back_pointer: + if (j, i) == (n-1, n-1): + print('*', end=' ') + else: + print('-', end=' ') + else: + print('*', end=' ') + if (j, i) == (n-1, n-1): + print('<-- End position', end=' ') + print() + print("^") + print("Start position") + print() + print("# is an obstacle") + print("- is the path taken by algorithm") +multi_a_star(start, goal, n_hueristic) diff --git a/Graphs/scc_kosaraju.py b/Graphs/scc_kosaraju.py new file mode 100644 index 000000000000..1f13ebaba36b --- /dev/null +++ b/Graphs/scc_kosaraju.py @@ -0,0 +1,46 @@ +from __future__ import print_function +# n - no of nodes, m - no of edges +n, m = list(map(int,input().split())) + +g = [[] for i in range(n)] #graph +r = [[] for i in range(n)] #reversed graph +# input graph data (edges) +for i in range(m): + u, v = list(map(int,input().split())) + g[u].append(v) + r[v].append(u) + +stack = [] +visit = [False]*n +scc = [] +component = [] + +def dfs(u): + global g, r, scc, component, visit, stack + if visit[u]: return + visit[u] = True + for v in g[u]: + dfs(v) + stack.append(u) + +def dfs2(u): + global g, r, scc, component, visit, stack + if visit[u]: return + visit[u] = True + component.append(u) + for v in r[u]: + dfs2(v) + +def kosaraju(): + global g, r, scc, component, visit, stack + for i in range(n): + dfs(i) + visit = [False]*n + for i in stack[::-1]: + if visit[i]: continue + component = [] + dfs2(i) + scc.append(component) + return scc + +print(kosaraju()) diff --git a/Graphs/tarjans_scc.py b/Graphs/tarjans_scc.py new file mode 100644 index 000000000000..89754e593508 --- /dev/null +++ b/Graphs/tarjans_scc.py @@ -0,0 +1,78 @@ +from collections import deque + + +def tarjan(g): + """ + Tarjan's algo for finding strongly connected components in a directed graph + + Uses two main attributes of each node to track reachability, the index of that node within a component(index), + and the lowest index reachable from that node(lowlink). + + We then perform a dfs of the each component making sure to update these parameters for each node and saving the + nodes we visit on the way. + + If ever we find that the lowest reachable node from a current node is equal to the index of the current node then it + must be the root of a strongly connected component and so we save it and it's equireachable vertices as a strongly + connected component. + + Complexity: strong_connect() is called at most once for each node and has a complexity of O(|E|) as it is DFS. + Therefore this has complexity O(|V| + |E|) for a graph G = (V, E) + + """ + + n = len(g) + stack = deque() + on_stack = [False for _ in range(n)] + index_of = [-1 for _ in range(n)] + lowlink_of = index_of[:] + + def strong_connect(v, index, components): + index_of[v] = index # the number when this node is seen + lowlink_of[v] = index # lowest rank node reachable from here + index += 1 + stack.append(v) + on_stack[v] = True + + for w in g[v]: + if index_of[w] == -1: + index = strong_connect(w, index, components) + lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] + elif on_stack[w]: + lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] + + if lowlink_of[v] == index_of[v]: + component = [] + w = stack.pop() + on_stack[w] = False + component.append(w) + while w != v: + w = stack.pop() + on_stack[w] = False + component.append(w) + components.append(component) + return index + + components = [] + for v in range(n): + if index_of[v] == -1: + strong_connect(v, 0, components) + + return components + + +def create_graph(n, edges): + g = [[] for _ in range(n)] + for u, v in edges: + g[u].append(v) + return g + + +if __name__ == '__main__': + # Test + n_vertices = 7 + source = [0, 0, 1, 2, 3, 3, 4, 4, 6] + target = [1, 3, 2, 0, 1, 4, 5, 6, 5] + edges = [(u, v) for u, v in zip(source, target)] + g = create_graph(n_vertices, edges) + + assert [[5], [6], [4], [3, 2, 1, 0]] == tarjan(g) From ec42dfdc858eec8ed112e0f465cb28c8f56993c9 Mon Sep 17 00:00:00 2001 From: Reshad-Hasan Date: Mon, 25 Feb 2019 14:33:43 +0600 Subject: [PATCH 3/4] all graph algorithms are in one folder --- graph algorithms/BFS.py | 39 -- graph algorithms/DFS.py | 36 -- ...irected and Undirected (Weighted) Graph.py | 468 ------------------ graph algorithms/a_star.py | 102 ---- graph algorithms/articulation_points.py | 44 -- graph algorithms/basic_graphs.py | 290 ----------- graph algorithms/bellman_ford.py | 54 -- graph algorithms/breadth_first_search.py | 67 --- graph algorithms/check_bipartite_graph_bfs.py | 43 -- graph algorithms/depth_first_search.py | 66 --- graph algorithms/dijkstra.py | 47 -- graph algorithms/dijkstra_2.py | 57 --- graph algorithms/dijkstra_algorithm.py | 212 -------- graph algorithms/even_tree.py | 70 --- graph algorithms/finding_bridges.py | 31 -- graph algorithms/floyd_warshall.py | 48 -- graph algorithms/graph.py | 44 -- graph algorithms/graph_list.py | 31 -- graph algorithms/graph_matrix.py | 32 -- graph algorithms/kahns_algorithm_long.py | 30 -- graph algorithms/kahns_algorithm_topo.py | 32 -- .../minimum_spanning_tree_kruskal.py | 32 -- .../minimum_spanning_tree_prims.py | 111 ----- graph algorithms/multi_hueristic_astar.py | 266 ---------- graph algorithms/scc_kosaraju.py | 46 -- graph algorithms/tarjans_scc.py | 78 --- 26 files changed, 2376 deletions(-) delete mode 100644 graph algorithms/BFS.py delete mode 100644 graph algorithms/DFS.py delete mode 100644 graph algorithms/Directed and Undirected (Weighted) Graph.py delete mode 100644 graph algorithms/a_star.py delete mode 100644 graph algorithms/articulation_points.py delete mode 100644 graph algorithms/basic_graphs.py delete mode 100644 graph algorithms/bellman_ford.py delete mode 100644 graph algorithms/breadth_first_search.py delete mode 100644 graph algorithms/check_bipartite_graph_bfs.py delete mode 100644 graph algorithms/depth_first_search.py delete mode 100644 graph algorithms/dijkstra.py delete mode 100644 graph algorithms/dijkstra_2.py delete mode 100644 graph algorithms/dijkstra_algorithm.py delete mode 100644 graph algorithms/even_tree.py delete mode 100644 graph algorithms/finding_bridges.py delete mode 100644 graph algorithms/floyd_warshall.py delete mode 100644 graph algorithms/graph.py delete mode 100644 graph algorithms/graph_list.py delete mode 100644 graph algorithms/graph_matrix.py delete mode 100644 graph algorithms/kahns_algorithm_long.py delete mode 100644 graph algorithms/kahns_algorithm_topo.py delete mode 100644 graph algorithms/minimum_spanning_tree_kruskal.py delete mode 100644 graph algorithms/minimum_spanning_tree_prims.py delete mode 100644 graph algorithms/multi_hueristic_astar.py delete mode 100644 graph algorithms/scc_kosaraju.py delete mode 100644 graph algorithms/tarjans_scc.py diff --git a/graph algorithms/BFS.py b/graph algorithms/BFS.py deleted file mode 100644 index bf9b572cec50..000000000000 --- a/graph algorithms/BFS.py +++ /dev/null @@ -1,39 +0,0 @@ -"""pseudo-code""" - -""" -BFS(graph G, start vertex s): -// all nodes initially unexplored -mark s as explored -let Q = queue data structure, initialized with s -while Q is non-empty: - remove the first node of Q, call it v - for each edge(v, w): // for w in graph[v] - if w unexplored: - mark w as explored - add w to Q (at the end) - -""" - -import collections - - -def bfs(graph, start): - explored, queue = set(), [start] # collections.deque([start]) - explored.add(start) - while queue: - v = queue.pop(0) # queue.popleft() - for w in graph[v]: - if w not in explored: - explored.add(w) - queue.append(w) - return explored - - -G = {'A': ['B', 'C'], - 'B': ['A', 'D', 'E'], - 'C': ['A', 'F'], - 'D': ['B'], - 'E': ['B', 'F'], - 'F': ['C', 'E']} - -print(bfs(G, 'A')) diff --git a/graph algorithms/DFS.py b/graph algorithms/DFS.py deleted file mode 100644 index d3c34fabb7b3..000000000000 --- a/graph algorithms/DFS.py +++ /dev/null @@ -1,36 +0,0 @@ -"""pseudo-code""" - -""" -DFS(graph G, start vertex s): -// all nodes initially unexplored -mark s as explored -for every edge (s, v): - if v unexplored: - DFS(G, v) -""" - - -def dfs(graph, start): - """The DFS function simply calls itself recursively for every unvisited child of its argument. We can emulate that - behaviour precisely using a stack of iterators. Instead of recursively calling with a node, we'll push an iterator - to the node's children onto the iterator stack. When the iterator at the top of the stack terminates, we'll pop - it off the stack.""" - explored, stack = set(), [start] - explored.add(start) - while stack: - v = stack.pop() # the only difference from BFS is to pop last element here instead of first one - for w in graph[v]: - if w not in explored: - explored.add(w) - stack.append(w) - return explored - - -G = {'A': ['B', 'C'], - 'B': ['A', 'D', 'E'], - 'C': ['A', 'F'], - 'D': ['B'], - 'E': ['B', 'F'], - 'F': ['C', 'E']} - -print(dfs(G, 'A')) diff --git a/graph algorithms/Directed and Undirected (Weighted) Graph.py b/graph algorithms/Directed and Undirected (Weighted) Graph.py deleted file mode 100644 index 68977de8d311..000000000000 --- a/graph algorithms/Directed and Undirected (Weighted) Graph.py +++ /dev/null @@ -1,468 +0,0 @@ -from collections import deque -import random as rand -import math as math -import time - -# the dfault weight is 1 if not assigend but all the implementation is weighted - -class DirectedGraph: - def __init__(self): - self.graph = {} - - # adding vertices and edges - # adding the weight is optional - # handels repetition - def add_pair(self, u, v, w = 1): - if self.graph.get(u): - if self.graph[u].count([w,v]) == 0: - self.graph[u].append([w, v]) - else: - self.graph[u] = [[w, v]] - if not self.graph.get(v): - self.graph[v] = [] - - def all_nodes(self): - return list(self.graph) - - # handels if the input does not exist - def remove_pair(self, u, v): - if self.graph.get(u): - for _ in self.graph[u]: - if _[1] == v: - self.graph[u].remove(_) - - # if no destination is meant the defaut value is -1 - def dfs(self, s = -2, d = -1): - if s == d: - return [] - stack = [] - visited = [] - if s == -2: - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - ss = s - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) < 1: - if __[1] == d: - visited.append(d) - return visited - else: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return visited - - # c is the count of nodes you want and if you leave it or pass -1 to the funtion the count - # will be random from 10 to 10000 - def fill_graph_randomly(self, c = -1): - if c == -1: - c = (math.floor(rand.random() * 10000)) + 10 - for _ in range(c): - # every vertex has max 100 edges - e = math.floor(rand.random() * 102) + 1 - for __ in range(e): - n = math.floor(rand.random() * (c)) + 1 - if n == _: - continue - self.add_pair(_, n, 1) - - def bfs(self, s = -2): - d = deque() - visited = [] - if s == -2: - s = list(self.graph.keys())[0] - d.append(s) - visited.append(s) - while d: - s = d.popleft() - if len(self.graph[s]) != 0: - for __ in self.graph[s]: - if visited.count(__[1]) < 1: - d.append(__[1]) - visited.append(__[1]) - return visited - def in_degree(self, u): - count = 0 - for _ in self.graph: - for __ in self.graph[_]: - if __[1] == u: - count += 1 - return count - - def out_degree(self, u): - return len(self.graph[u]) - - def topological_sort(self, s = -2): - stack = [] - visited = [] - if s == -2: - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - ss = s - sorted_nodes = [] - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) < 1: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - sorted_nodes.append(stack.pop()) - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return sorted_nodes - - def cycle_nodes(self): - stack = [] - visited = [] - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: - l = len(stack) - 1 - while True and l >= 0: - if stack[l] == __[1]: - anticipating_nodes.add(__[1]) - break - else: - anticipating_nodes.add(stack[l]) - l -= 1 - if visited.count(__[1]) < 1: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return list(anticipating_nodes) - - def has_cycle(self): - stack = [] - visited = [] - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: - l = len(stack) - 1 - while True and l >= 0: - if stack[l] == __[1]: - anticipating_nodes.add(__[1]) - break - else: - return True - anticipating_nodes.add(stack[l]) - l -= 1 - if visited.count(__[1]) < 1: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return False - - def dfs_time(self, s = -2, e = -1): - begin = time.time() - self.dfs(s,e) - end = time.time() - return end - begin - - def bfs_time(self, s = -2): - begin = time.time() - self.bfs(s) - end = time.time() - return end - begin - -class Graph: - def __init__(self): - self.graph = {} - - # adding vertices and edges - # adding the weight is optional - # handels repetition - def add_pair(self, u, v, w = 1): - # check if the u exists - if self.graph.get(u): - # if there already is a edge - if self.graph[u].count([w,v]) == 0: - self.graph[u].append([w, v]) - else: - # if u does not exist - self.graph[u] = [[w, v]] - # add the other way - if self.graph.get(v): - # if there already is a edge - if self.graph[v].count([w,u]) == 0: - self.graph[v].append([w, u]) - else: - # if u does not exist - self.graph[v] = [[w, u]] - - # handels if the input does not exist - def remove_pair(self, u, v): - if self.graph.get(u): - for _ in self.graph[u]: - if _[1] == v: - self.graph[u].remove(_) - # the other way round - if self.graph.get(v): - for _ in self.graph[v]: - if _[1] == u: - self.graph[v].remove(_) - - # if no destination is meant the defaut value is -1 - def dfs(self, s = -2, d = -1): - if s == d: - return [] - stack = [] - visited = [] - if s == -2: - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - ss = s - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) < 1: - if __[1] == d: - visited.append(d) - return visited - else: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return visited - - # c is the count of nodes you want and if you leave it or pass -1 to the funtion the count - # will be random from 10 to 10000 - def fill_graph_randomly(self, c = -1): - if c == -1: - c = (math.floor(rand.random() * 10000)) + 10 - for _ in range(c): - # every vertex has max 100 edges - e = math.floor(rand.random() * 102) + 1 - for __ in range(e): - n = math.floor(rand.random() * (c)) + 1 - if n == _: - continue - self.add_pair(_, n, 1) - - def bfs(self, s = -2): - d = deque() - visited = [] - if s == -2: - s = list(self.graph.keys())[0] - d.append(s) - visited.append(s) - while d: - s = d.popleft() - if len(self.graph[s]) != 0: - for __ in self.graph[s]: - if visited.count(__[1]) < 1: - d.append(__[1]) - visited.append(__[1]) - return visited - def degree(self, u): - return len(self.graph[u]) - - def cycle_nodes(self): - stack = [] - visited = [] - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: - l = len(stack) - 1 - while True and l >= 0: - if stack[l] == __[1]: - anticipating_nodes.add(__[1]) - break - else: - anticipating_nodes.add(stack[l]) - l -= 1 - if visited.count(__[1]) < 1: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return list(anticipating_nodes) - - def has_cycle(self): - stack = [] - visited = [] - s = list(self.graph.keys())[0] - stack.append(s) - visited.append(s) - parent = -2 - indirect_parents = [] - ss = s - anticipating_nodes = set() - - while True: - # check if there is any non isolated nodes - if len(self.graph[s]) != 0: - ss = s - for __ in self.graph[s]: - if visited.count(__[1]) > 0 and __[1] != parent and indirect_parents.count(__[1]) > 0 and not on_the_way_back: - l = len(stack) - 1 - while True and l >= 0: - if stack[l] == __[1]: - anticipating_nodes.add(__[1]) - break - else: - return True - anticipating_nodes.add(stack[l]) - l -= 1 - if visited.count(__[1]) < 1: - stack.append(__[1]) - visited.append(__[1]) - ss =__[1] - break - - # check if all the children are visited - if s == ss : - stack.pop() - on_the_way_back = True - if len(stack) != 0: - s = stack[len(stack) - 1] - else: - on_the_way_back = False - indirect_parents.append(parent) - parent = s - s = ss - - # check if se have reached the starting point - if len(stack) == 0: - return False - def all_nodes(self): - return list(self.graph) - - def dfs_time(self, s = -2, e = -1): - begin = time.time() - self.dfs(s,e) - end = time.time() - return end - begin - - def bfs_time(self, s = -2): - begin = time.time() - self.bfs(s) - end = time.time() - return end - begin diff --git a/graph algorithms/a_star.py b/graph algorithms/a_star.py deleted file mode 100644 index 584222e6f62b..000000000000 --- a/graph algorithms/a_star.py +++ /dev/null @@ -1,102 +0,0 @@ -from __future__ import print_function - -grid = [[0, 1, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0],#0 are free path whereas 1's are obstacles - [0, 1, 0, 0, 0, 0], - [0, 1, 0, 0, 1, 0], - [0, 0, 0, 0, 1, 0]] - -''' -heuristic = [[9, 8, 7, 6, 5, 4], - [8, 7, 6, 5, 4, 3], - [7, 6, 5, 4, 3, 2], - [6, 5, 4, 3, 2, 1], - [5, 4, 3, 2, 1, 0]]''' - -init = [0, 0] -goal = [len(grid)-1, len(grid[0])-1] #all coordinates are given in format [y,x] -cost = 1 - -#the cost map which pushes the path closer to the goal -heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))] -for i in range(len(grid)): - for j in range(len(grid[0])): - heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1]) - if grid[i][j] == 1: - heuristic[i][j] = 99 #added extra penalty in the heuristic map - - -#the actions we can take -delta = [[-1, 0 ], # go up - [ 0, -1], # go left - [ 1, 0 ], # go down - [ 0, 1 ]] # go right - - -#function to search the path -def search(grid,init,goal,cost,heuristic): - - closed = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]# the referrence grid - closed[init[0]][init[1]] = 1 - action = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]#the action grid - - x = init[0] - y = init[1] - g = 0 - f = g + heuristic[init[0]][init[0]] - cell = [[f, g, x, y]] - - found = False # flag that is set when search is complete - resign = False # flag set if we can't find expand - - while not found and not resign: - if len(cell) == 0: - resign = True - return "FAIL" - else: - cell.sort()#to choose the least costliest action so as to move closer to the goal - cell.reverse() - next = cell.pop() - x = next[2] - y = next[3] - g = next[1] - f = next[0] - - - if x == goal[0] and y == goal[1]: - found = True - else: - for i in range(len(delta)):#to try out different valid actions - x2 = x + delta[i][0] - y2 = y + delta[i][1] - if x2 >= 0 and x2 < len(grid) and y2 >=0 and y2 < len(grid[0]): - if closed[x2][y2] == 0 and grid[x2][y2] == 0: - g2 = g + cost - f2 = g2 + heuristic[x2][y2] - cell.append([f2, g2, x2, y2]) - closed[x2][y2] = 1 - action[x2][y2] = i - invpath = [] - x = goal[0] - y = goal[1] - invpath.append([x, y])#we get the reverse path from here - while x != init[0] or y != init[1]: - x2 = x - delta[action[x][y]][0] - y2 = y - delta[action[x][y]][1] - x = x2 - y = y2 - invpath.append([x, y]) - - path = [] - for i in range(len(invpath)): - path.append(invpath[len(invpath) - 1 - i]) - print("ACTION MAP") - for i in range(len(action)): - print(action[i]) - - return path - -a = search(grid,init,goal,cost,heuristic) -for i in range(len(a)): - print(a[i]) - diff --git a/graph algorithms/articulation_points.py b/graph algorithms/articulation_points.py deleted file mode 100644 index 1173c4ea373c..000000000000 --- a/graph algorithms/articulation_points.py +++ /dev/null @@ -1,44 +0,0 @@ -# Finding Articulation Points in Undirected Graph -def computeAP(l): - n = len(l) - outEdgeCount = 0 - low = [0] * n - visited = [False] * n - isArt = [False] * n - - def dfs(root, at, parent, outEdgeCount): - if parent == root: - outEdgeCount += 1 - visited[at] = True - low[at] = at - - for to in l[at]: - if to == parent: - pass - elif not visited[to]: - outEdgeCount = dfs(root, to, at, outEdgeCount) - low[at] = min(low[at], low[to]) - - # AP found via bridge - if at < low[to]: - isArt[at] = True - # AP found via cycle - if at == low[to]: - isArt[at] = True - else: - low[at] = min(low[at], to) - return outEdgeCount - - for i in range(n): - if not visited[i]: - outEdgeCount = 0 - outEdgeCount = dfs(i, i, -1, outEdgeCount) - isArt[i] = (outEdgeCount > 1) - - for x in range(len(isArt)): - if isArt[x] == True: - print(x) - -# Adjacency list of graph -l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]} -computeAP(l) diff --git a/graph algorithms/basic_graphs.py b/graph algorithms/basic_graphs.py deleted file mode 100644 index 3b3abeb1720d..000000000000 --- a/graph algorithms/basic_graphs.py +++ /dev/null @@ -1,290 +0,0 @@ -from __future__ import print_function - -try: - raw_input # Python 2 -except NameError: - raw_input = input # Python 3 - -try: - xrange # Python 2 -except NameError: - xrange = range # Python 3 - -# Accept No. of Nodes and edges -n, m = map(int, raw_input().split(" ")) - -# Initialising Dictionary of edges -g = {} -for i in xrange(n): - g[i + 1] = [] - -""" --------------------------------------------------------------------------------- - Accepting edges of Unweighted Directed Graphs --------------------------------------------------------------------------------- -""" -for _ in xrange(m): - x, y = map(int, raw_input().split(" ")) - g[x].append(y) - -""" --------------------------------------------------------------------------------- - Accepting edges of Unweighted Undirected Graphs --------------------------------------------------------------------------------- -""" -for _ in xrange(m): - x, y = map(int, raw_input().split(" ")) - g[x].append(y) - g[y].append(x) - -""" --------------------------------------------------------------------------------- - Accepting edges of Weighted Undirected Graphs --------------------------------------------------------------------------------- -""" -for _ in xrange(m): - x, y, r = map(int, raw_input().split(" ")) - g[x].append([y, r]) - g[y].append([x, r]) - -""" --------------------------------------------------------------------------------- - Depth First Search. - Args : G - Dictionary of edges - s - Starting Node - Vars : vis - Set of visited nodes - S - Traversal Stack --------------------------------------------------------------------------------- -""" - - -def dfs(G, s): - vis, S = set([s]), [s] - print(s) - while S: - flag = 0 - for i in G[S[-1]]: - if i not in vis: - S.append(i) - vis.add(i) - flag = 1 - print(i) - break - if not flag: - S.pop() - - -""" --------------------------------------------------------------------------------- - Breadth First Search. - Args : G - Dictionary of edges - s - Starting Node - Vars : vis - Set of visited nodes - Q - Traveral Stack --------------------------------------------------------------------------------- -""" -from collections import deque - - -def bfs(G, s): - vis, Q = set([s]), deque([s]) - print(s) - while Q: - u = Q.popleft() - for v in G[u]: - if v not in vis: - vis.add(v) - Q.append(v) - print(v) - - -""" --------------------------------------------------------------------------------- - Dijkstra's shortest path Algorithm - Args : G - Dictionary of edges - s - Starting Node - Vars : dist - Dictionary storing shortest distance from s to every other node - known - Set of knows nodes - path - Preceding node in path --------------------------------------------------------------------------------- -""" - - -def dijk(G, s): - dist, known, path = {s: 0}, set(), {s: 0} - while True: - if len(known) == len(G) - 1: - break - mini = 100000 - for i in dist: - if i not in known and dist[i] < mini: - mini = dist[i] - u = i - known.add(u) - for v in G[u]: - if v[0] not in known: - if dist[u] + v[1] < dist.get(v[0], 100000): - dist[v[0]] = dist[u] + v[1] - path[v[0]] = u - for i in dist: - if i != s: - print(dist[i]) - - -""" --------------------------------------------------------------------------------- - Topological Sort --------------------------------------------------------------------------------- -""" -from collections import deque - - -def topo(G, ind=None, Q=[1]): - if ind is None: - ind = [0] * (len(G) + 1) # SInce oth Index is ignored - for u in G: - for v in G[u]: - ind[v] += 1 - Q = deque() - for i in G: - if ind[i] == 0: - Q.append(i) - if len(Q) == 0: - return - v = Q.popleft() - print(v) - for w in G[v]: - ind[w] -= 1 - if ind[w] == 0: - Q.append(w) - topo(G, ind, Q) - - -""" --------------------------------------------------------------------------------- - Reading an Adjacency matrix --------------------------------------------------------------------------------- -""" - - -def adjm(): - n, a = raw_input(), [] - for i in xrange(n): - a.append(map(int, raw_input().split())) - return a, n - - -""" --------------------------------------------------------------------------------- - Floyd Warshall's algorithm - Args : G - Dictionary of edges - s - Starting Node - Vars : dist - Dictionary storing shortest distance from s to every other node - known - Set of knows nodes - path - Preceding node in path - --------------------------------------------------------------------------------- -""" - - -def floy(A_and_n): - (A, n) = A_and_n - dist = list(A) - path = [[0] * n for i in xrange(n)] - for k in xrange(n): - for i in xrange(n): - for j in xrange(n): - if dist[i][j] > dist[i][k] + dist[k][j]: - dist[i][j] = dist[i][k] + dist[k][j] - path[i][k] = k - print(dist) - - -""" --------------------------------------------------------------------------------- - Prim's MST Algorithm - Args : G - Dictionary of edges - s - Starting Node - Vars : dist - Dictionary storing shortest distance from s to nearest node - known - Set of knows nodes - path - Preceding node in path --------------------------------------------------------------------------------- -""" - - -def prim(G, s): - dist, known, path = {s: 0}, set(), {s: 0} - while True: - if len(known) == len(G) - 1: - break - mini = 100000 - for i in dist: - if i not in known and dist[i] < mini: - mini = dist[i] - u = i - known.add(u) - for v in G[u]: - if v[0] not in known: - if v[1] < dist.get(v[0], 100000): - dist[v[0]] = v[1] - path[v[0]] = u - - -""" --------------------------------------------------------------------------------- - Accepting Edge list - Vars : n - Number of nodes - m - Number of edges - Returns : l - Edge list - n - Number of Nodes --------------------------------------------------------------------------------- -""" - - -def edglist(): - n, m = map(int, raw_input().split(" ")) - l = [] - for i in xrange(m): - l.append(map(int, raw_input().split(' '))) - return l, n - - -""" --------------------------------------------------------------------------------- - Kruskal's MST Algorithm - Args : E - Edge list - n - Number of Nodes - Vars : s - Set of all nodes as unique disjoint sets (initially) --------------------------------------------------------------------------------- -""" - - -def krusk(E_and_n): - # Sort edges on the basis of distance - (E, n) = E_and_n - E.sort(reverse=True, key=lambda x: x[2]) - s = [set([i]) for i in range(1, n + 1)] - while True: - if len(s) == 1: - break - print(s) - x = E.pop() - for i in xrange(len(s)): - if x[0] in s[i]: - break - for j in xrange(len(s)): - if x[1] in s[j]: - if i == j: - break - s[j].update(s[i]) - s.pop(i) - break - - -# find the isolated node in the graph -def find_isolated_nodes(graph): - isolated = [] - for node in graph: - if not graph[node]: - isolated.append(node) - return isolated diff --git a/graph algorithms/bellman_ford.py b/graph algorithms/bellman_ford.py deleted file mode 100644 index 82db80546b94..000000000000 --- a/graph algorithms/bellman_ford.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import print_function - -def printDist(dist, V): - print("\nVertex Distance") - for i in range(V): - if dist[i] != float('inf') : - print(i,"\t",int(dist[i]),end = "\t") - else: - print(i,"\t","INF",end="\t") - print() - -def BellmanFord(graph, V, E, src): - mdist=[float('inf') for i in range(V)] - mdist[src] = 0.0 - - for i in range(V-1): - for j in range(V): - u = graph[j]["src"] - v = graph[j]["dst"] - w = graph[j]["weight"] - - if mdist[u] != float('inf') and mdist[u] + w < mdist[v]: - mdist[v] = mdist[u] + w - for j in range(V): - u = graph[j]["src"] - v = graph[j]["dst"] - w = graph[j]["weight"] - - if mdist[u] != float('inf') and mdist[u] + w < mdist[v]: - print("Negative cycle found. Solution not possible.") - return - - printDist(mdist, V) - - - -#MAIN -V = int(input("Enter number of vertices: ")) -E = int(input("Enter number of edges: ")) - -graph = [dict() for j in range(E)] - -for i in range(V): - graph[i][i] = 0.0 - -for i in range(E): - print("\nEdge ",i+1) - src = int(input("Enter source:")) - dst = int(input("Enter destination:")) - weight = float(input("Enter weight:")) - graph[i] = {"src": src,"dst": dst, "weight": weight} - -gsrc = int(input("\nEnter shortest path source:")) -BellmanFord(graph, V, E, gsrc) diff --git a/graph algorithms/breadth_first_search.py b/graph algorithms/breadth_first_search.py deleted file mode 100644 index 3992e2d4d892..000000000000 --- a/graph algorithms/breadth_first_search.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python -# encoding=utf8 - -""" Author: OMKAR PATHAK """ - -from __future__ import print_function - - -class Graph(): - def __init__(self): - self.vertex = {} - - # for printing the Graph vertexes - def printGraph(self): - for i in self.vertex.keys(): - print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) - - # for adding the edge beween two vertexes - def addEdge(self, fromVertex, toVertex): - # check if vertex is already present, - if fromVertex in self.vertex.keys(): - self.vertex[fromVertex].append(toVertex) - else: - # else make a new vertex - self.vertex[fromVertex] = [toVertex] - - def BFS(self, startVertex): - # Take a list for stoting already visited vertexes - visited = [False] * len(self.vertex) - - # create a list to store all the vertexes for BFS - queue = [] - - # mark the source node as visited and enqueue it - visited[startVertex] = True - queue.append(startVertex) - - while queue: - startVertex = queue.pop(0) - print(startVertex, end = ' ') - - # mark all adjacent nodes as visited and print them - for i in self.vertex[startVertex]: - if visited[i] == False: - queue.append(i) - visited[i] = True - -if __name__ == '__main__': - g = Graph() - g.addEdge(0, 1) - g.addEdge(0, 2) - g.addEdge(1, 2) - g.addEdge(2, 0) - g.addEdge(2, 3) - g.addEdge(3, 3) - - g.printGraph() - print('BFS:') - g.BFS(2) - - # OUTPUT: - # 0  ->  1 -> 2 - # 1  ->  2 - # 2  ->  0 -> 3 - # 3  ->  3 - # BFS: - # 2 0 3 1 diff --git a/graph algorithms/check_bipartite_graph_bfs.py b/graph algorithms/check_bipartite_graph_bfs.py deleted file mode 100644 index 1b9c32c6ccc4..000000000000 --- a/graph algorithms/check_bipartite_graph_bfs.py +++ /dev/null @@ -1,43 +0,0 @@ -# Check whether Graph is Bipartite or Not using BFS - -# A Bipartite Graph is a graph whose vertices can be divided into two independent sets, -# U and V such that every edge (u, v) either connects a vertex from U to V or a vertex -# from V to U. In other words, for every edge (u, v), either u belongs to U and v to V, -# or u belongs to V and v to U. We can also say that there is no edge that connects -# vertices of same set. -def checkBipartite(l): - queue = [] - visited = [False] * len(l) - color = [-1] * len(l) - - def bfs(): - while(queue): - u = queue.pop(0) - visited[u] = True - - for neighbour in l[u]: - - if neighbour == u: - return False - - if color[neighbour] == -1: - color[neighbour] = 1 - color[u] - queue.append(neighbour) - - elif color[neighbour] == color[u]: - return False - - return True - - for i in range(len(l)): - if not visited[i]: - queue.append(i) - color[i] = 0 - if bfs() == False: - return False - - return True - -# Adjacency List of graph -l = {0:[1,3], 1:[0,2], 2:[1,3], 3:[0,2]} -print(checkBipartite(l)) diff --git a/graph algorithms/depth_first_search.py b/graph algorithms/depth_first_search.py deleted file mode 100644 index 98faf61354f9..000000000000 --- a/graph algorithms/depth_first_search.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/python -# encoding=utf8 - -""" Author: OMKAR PATHAK """ -from __future__ import print_function - - -class Graph(): - def __init__(self): - self.vertex = {} - - # for printing the Graph vertexes - def printGraph(self): - print(self.vertex) - for i in self.vertex.keys(): - print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) - - # for adding the edge beween two vertexes - def addEdge(self, fromVertex, toVertex): - # check if vertex is already present, - if fromVertex in self.vertex.keys(): - self.vertex[fromVertex].append(toVertex) - else: - # else make a new vertex - self.vertex[fromVertex] = [toVertex] - - def DFS(self): - # visited array for storing already visited nodes - visited = [False] * len(self.vertex) - - # call the recursive helper function - for i in range(len(self.vertex)): - if visited[i] == False: - self.DFSRec(i, visited) - - def DFSRec(self, startVertex, visited): - # mark start vertex as visited - visited[startVertex] = True - - print(startVertex, end = ' ') - - # Recur for all the vertexes that are adjacent to this node - for i in self.vertex.keys(): - if visited[i] == False: - self.DFSRec(i, visited) - -if __name__ == '__main__': - g = Graph() - g.addEdge(0, 1) - g.addEdge(0, 2) - g.addEdge(1, 2) - g.addEdge(2, 0) - g.addEdge(2, 3) - g.addEdge(3, 3) - - g.printGraph() - print('DFS:') - g.DFS() - - # OUTPUT: - # 0  ->  1 -> 2 - # 1  ->  2 - # 2  ->  0 -> 3 - # 3  ->  3 - # DFS: - # 0 1 2 3 diff --git a/graph algorithms/dijkstra.py b/graph algorithms/dijkstra.py deleted file mode 100644 index 6b08b28fcfd3..000000000000 --- a/graph algorithms/dijkstra.py +++ /dev/null @@ -1,47 +0,0 @@ -"""pseudo-code""" - -""" -DIJKSTRA(graph G, start vertex s,destination vertex d): -// all nodes initially unexplored -let H = min heap data structure, initialized with 0 and s [here 0 indicates the distance from start vertex] -while H is non-empty: - remove the first node and cost of H, call it U and cost - if U is not explored - mark U as explored - if U is d: - return cost // total cost from start to destination vertex - for each edge(U, V): c=cost of edge(u,V) // for V in graph[U] - if V unexplored: - next=cost+c - add next,V to H (at the end) -""" -import heapq - - -def dijkstra(graph, start, end): - heap = [(0, start)] # cost from start node,end node - visited = [] - while heap: - (cost, u) = heapq.heappop(heap) - if u in visited: - continue - visited.append(u) - if u == end: - return cost - for v, c in G[u]: - if v in visited: - continue - next = cost + c - heapq.heappush(heap, (next, v)) - return (-1, -1) - - -G = {'A': [['B', 2], ['C', 5]], - 'B': [['A', 2], ['D', 3], ['E', 1]], - 'C': [['A', 5], ['F', 3]], - 'D': [['B', 3]], - 'E': [['B', 1], ['F', 3]], - 'F': [['C', 3], ['E', 3]]} - -shortDistance = dijkstra(G, 'E', 'C') -print(shortDistance) diff --git a/graph algorithms/dijkstra_2.py b/graph algorithms/dijkstra_2.py deleted file mode 100644 index a6c340e8a68d..000000000000 --- a/graph algorithms/dijkstra_2.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import print_function - -def printDist(dist, V): - print("\nVertex Distance") - for i in range(V): - if dist[i] != float('inf') : - print(i,"\t",int(dist[i]),end = "\t") - else: - print(i,"\t","INF",end="\t") - print() - -def minDist(mdist, vset, V): - minVal = float('inf') - minInd = -1 - for i in range(V): - if (not vset[i]) and mdist[i] < minVal : - minInd = i - minVal = mdist[i] - return minInd - -def Dijkstra(graph, V, src): - mdist=[float('inf') for i in range(V)] - vset = [False for i in range(V)] - mdist[src] = 0.0 - - for i in range(V-1): - u = minDist(mdist, vset, V) - vset[u] = True - - for v in range(V): - if (not vset[v]) and graph[u][v]!=float('inf') and mdist[u] + graph[u][v] < mdist[v]: - mdist[v] = mdist[u] + graph[u][v] - - - - printDist(mdist, V) - - - -#MAIN -V = int(input("Enter number of vertices: ")) -E = int(input("Enter number of edges: ")) - -graph = [[float('inf') for i in range(V)] for j in range(V)] - -for i in range(V): - graph[i][i] = 0.0 - -for i in range(E): - print("\nEdge ",i+1) - src = int(input("Enter source:")) - dst = int(input("Enter destination:")) - weight = float(input("Enter weight:")) - graph[src][dst] = weight - -gsrc = int(input("\nEnter shortest path source:")) -Dijkstra(graph, V, gsrc) diff --git a/graph algorithms/dijkstra_algorithm.py b/graph algorithms/dijkstra_algorithm.py deleted file mode 100644 index 985c7f6c1301..000000000000 --- a/graph algorithms/dijkstra_algorithm.py +++ /dev/null @@ -1,212 +0,0 @@ -# Title: Dijkstra's Algorithm for finding single source shortest path from scratch -# Author: Shubham Malik -# References: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm - -from __future__ import print_function -import math -import sys -# For storing the vertex set to retreive node with the lowest distance - - -class PriorityQueue: - # Based on Min Heap - def __init__(self): - self.cur_size = 0 - self.array = [] - self.pos = {} # To store the pos of node in array - - def isEmpty(self): - return self.cur_size == 0 - - def min_heapify(self, idx): - lc = self.left(idx) - rc = self.right(idx) - if lc < self.cur_size and self.array(lc)[0] < self.array(idx)[0]: - smallest = lc - else: - smallest = idx - if rc < self.cur_size and self.array(rc)[0] < self.array(smallest)[0]: - smallest = rc - if smallest != idx: - self.swap(idx, smallest) - self.min_heapify(smallest) - - def insert(self, tup): - # Inserts a node into the Priority Queue - self.pos[tup[1]] = self.cur_size - self.cur_size += 1 - self.array.append((sys.maxsize, tup[1])) - self.decrease_key((sys.maxsize, tup[1]), tup[0]) - - def extract_min(self): - # Removes and returns the min element at top of priority queue - min_node = self.array[0][1] - self.array[0] = self.array[self.cur_size - 1] - self.cur_size -= 1 - self.min_heapify(1) - del self.pos[min_node] - return min_node - - def left(self, i): - # returns the index of left child - return 2 * i + 1 - - def right(self, i): - # returns the index of right child - return 2 * i + 2 - - def par(self, i): - # returns the index of parent - return math.floor(i / 2) - - def swap(self, i, j): - # swaps array elements at indices i and j - # update the pos{} - self.pos[self.array[i][1]] = j - self.pos[self.array[j][1]] = i - temp = self.array[i] - self.array[i] = self.array[j] - self.array[j] = temp - - def decrease_key(self, tup, new_d): - idx = self.pos[tup[1]] - # assuming the new_d is atmost old_d - self.array[idx] = (new_d, tup[1]) - while idx > 0 and self.array[self.par(idx)][0] > self.array[idx][0]: - self.swap(idx, self.par(idx)) - idx = self.par(idx) - - -class Graph: - def __init__(self, num): - self.adjList = {} # To store graph: u -> (v,w) - self.num_nodes = num # Number of nodes in graph - # To store the distance from source vertex - self.dist = [0] * self.num_nodes - self.par = [-1] * self.num_nodes # To store the path - - def add_edge(self, u, v, w): - # Edge going from node u to v and v to u with weight w - # u (w)-> v, v (w) -> u - # Check if u already in graph - if u in self.adjList.keys(): - self.adjList[u].append((v, w)) - else: - self.adjList[u] = [(v, w)] - - # Assuming undirected graph - if v in self.adjList.keys(): - self.adjList[v].append((u, w)) - else: - self.adjList[v] = [(u, w)] - - def show_graph(self): - # u -> v(w) - for u in self.adjList: - print(u, '->', ' -> '.join(str("{}({})".format(v, w)) - for v, w in self.adjList[u])) - - def dijkstra(self, src): - # Flush old junk values in par[] - self.par = [-1] * self.num_nodes - # src is the source node - self.dist[src] = 0 - Q = PriorityQueue() - Q.insert((0, src)) # (dist from src, node) - for u in self.adjList.keys(): - if u != src: - self.dist[u] = sys.maxsize # Infinity - self.par[u] = -1 - - while not Q.isEmpty(): - u = Q.extract_min() # Returns node with the min dist from source - # Update the distance of all the neighbours of u and - # if their prev dist was INFINITY then push them in Q - for v, w in self.adjList[u]: - new_dist = self.dist[u] + w - if self.dist[v] > new_dist: - if self.dist[v] == sys.maxsize: - Q.insert((new_dist, v)) - else: - Q.decrease_key((self.dist[v], v), new_dist) - self.dist[v] = new_dist - self.par[v] = u - - # Show the shortest distances from src - self.show_distances(src) - - def show_distances(self, src): - print("Distance from node: {}".format(src)) - for u in range(self.num_nodes): - print('Node {} has distance: {}'.format(u, self.dist[u])) - - def show_path(self, src, dest): - # To show the shortest path from src to dest - # WARNING: Use it *after* calling dijkstra - path = [] - cost = 0 - temp = dest - # Backtracking from dest to src - while self.par[temp] != -1: - path.append(temp) - if temp != src: - for v, w in self.adjList[temp]: - if v == self.par[temp]: - cost += w - break - temp = self.par[temp] - path.append(src) - path.reverse() - - print('----Path to reach {} from {}----'.format(dest, src)) - for u in path: - print('{}'.format(u), end=' ') - if u != dest: - print('-> ', end='') - - print('\nTotal cost of path: ', cost) - - -if __name__ == '__main__': - graph = Graph(9) - graph.add_edge(0, 1, 4) - graph.add_edge(0, 7, 8) - graph.add_edge(1, 2, 8) - graph.add_edge(1, 7, 11) - graph.add_edge(2, 3, 7) - graph.add_edge(2, 8, 2) - graph.add_edge(2, 5, 4) - graph.add_edge(3, 4, 9) - graph.add_edge(3, 5, 14) - graph.add_edge(4, 5, 10) - graph.add_edge(5, 6, 2) - graph.add_edge(6, 7, 1) - graph.add_edge(6, 8, 6) - graph.add_edge(7, 8, 7) - graph.show_graph() - graph.dijkstra(0) - graph.show_path(0, 4) - -# OUTPUT -# 0 -> 1(4) -> 7(8) -# 1 -> 0(4) -> 2(8) -> 7(11) -# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7) -# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4) -# 3 -> 2(7) -> 4(9) -> 5(14) -# 8 -> 2(2) -> 6(6) -> 7(7) -# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2) -# 4 -> 3(9) -> 5(10) -# 6 -> 5(2) -> 7(1) -> 8(6) -# Distance from node: 0 -# Node 0 has distance: 0 -# Node 1 has distance: 4 -# Node 2 has distance: 12 -# Node 3 has distance: 19 -# Node 4 has distance: 21 -# Node 5 has distance: 11 -# Node 6 has distance: 9 -# Node 7 has distance: 8 -# Node 8 has distance: 14 -# ----Path to reach 4 from 0---- -# 0 -> 7 -> 6 -> 5 -> 4 -# Total cost of path: 21 diff --git a/graph algorithms/even_tree.py b/graph algorithms/even_tree.py deleted file mode 100644 index 9383ea9a13c1..000000000000 --- a/graph algorithms/even_tree.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -You are given a tree(a simple connected graph with no cycles). The tree has N -nodes numbered from 1 to N and is rooted at node 1. - -Find the maximum number of edges you can remove from the tree to get a forest -such that each connected component of the forest contains an even number of -nodes. - -Constraints -2 <= 2 <= 100 - -Note: The tree input will be such that it can always be decomposed into -components containing an even number of nodes. -""" -from __future__ import print_function -# pylint: disable=invalid-name -from collections import defaultdict - - -def dfs(start): - """DFS traversal""" - # pylint: disable=redefined-outer-name - ret = 1 - visited[start] = True - for v in tree.get(start): - if v not in visited: - ret += dfs(v) - if ret % 2 == 0: - cuts.append(start) - return ret - - -def even_tree(): - """ - 2 1 - 3 1 - 4 3 - 5 2 - 6 1 - 7 2 - 8 6 - 9 8 - 10 8 - On removing edges (1,3) and (1,6), we can get the desired result 2. - """ - dfs(1) - - -if __name__ == '__main__': - n, m = 10, 9 - tree = defaultdict(list) - visited = {} - cuts = [] - count = 0 - edges = [ - (2, 1), - (3, 1), - (4, 3), - (5, 2), - (6, 1), - (7, 2), - (8, 6), - (9, 8), - (10, 8), - ] - for u, v in edges: - tree[u].append(v) - tree[v].append(u) - even_tree() - print(len(cuts) - 1) diff --git a/graph algorithms/finding_bridges.py b/graph algorithms/finding_bridges.py deleted file mode 100644 index 56533dd48bde..000000000000 --- a/graph algorithms/finding_bridges.py +++ /dev/null @@ -1,31 +0,0 @@ -# Finding Bridges in Undirected Graph -def computeBridges(l): - id = 0 - n = len(l) # No of vertices in graph - low = [0] * n - visited = [False] * n - - def dfs(at, parent, bridges, id): - visited[at] = True - low[at] = id - id += 1 - for to in l[at]: - if to == parent: - pass - elif not visited[to]: - dfs(to, at, bridges, id) - low[at] = min(low[at], low[to]) - if at < low[to]: - bridges.append([at, to]) - else: - # This edge is a back edge and cannot be a bridge - low[at] = min(low[at], to) - - bridges = [] - for i in range(n): - if (not visited[i]): - dfs(i, -1, bridges, id) - print(bridges) - -l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]} -computeBridges(l) diff --git a/graph algorithms/floyd_warshall.py b/graph algorithms/floyd_warshall.py deleted file mode 100644 index fae8b19b351a..000000000000 --- a/graph algorithms/floyd_warshall.py +++ /dev/null @@ -1,48 +0,0 @@ -from __future__ import print_function - -def printDist(dist, V): - print("\nThe shortest path matrix using Floyd Warshall algorithm\n") - for i in range(V): - for j in range(V): - if dist[i][j] != float('inf') : - print(int(dist[i][j]),end = "\t") - else: - print("INF",end="\t") - print() - - - -def FloydWarshall(graph, V): - dist=[[float('inf') for i in range(V)] for j in range(V)] - - for i in range(V): - for j in range(V): - dist[i][j] = graph[i][j] - - for k in range(V): - for i in range(V): - for j in range(V): - if dist[i][k]!=float('inf') and dist[k][j]!=float('inf') and dist[i][k]+dist[k][j] < dist[i][j]: - dist[i][j] = dist[i][k] + dist[k][j] - - printDist(dist, V) - - - -#MAIN -V = int(input("Enter number of vertices: ")) -E = int(input("Enter number of edges: ")) - -graph = [[float('inf') for i in range(V)] for j in range(V)] - -for i in range(V): - graph[i][i] = 0.0 - -for i in range(E): - print("\nEdge ",i+1) - src = int(input("Enter source:")) - dst = int(input("Enter destination:")) - weight = float(input("Enter weight:")) - graph[src][dst] = weight - -FloydWarshall(graph, V) diff --git a/graph algorithms/graph.py b/graph algorithms/graph.py deleted file mode 100644 index 9bd61559dcbf..000000000000 --- a/graph algorithms/graph.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/python -# encoding=utf8 - -from __future__ import print_function -# Author: OMKAR PATHAK - -# We can use Python's dictionary for constructing the graph - -class AdjacencyList(object): - def __init__(self): - self.List = {} - - def addEdge(self, fromVertex, toVertex): - # check if vertex is already present - if fromVertex in self.List.keys(): - self.List[fromVertex].append(toVertex) - else: - self.List[fromVertex] = [toVertex] - - def printList(self): - for i in self.List: - print((i,'->',' -> '.join([str(j) for j in self.List[i]]))) - -if __name__ == '__main__': - al = AdjacencyList() - al.addEdge(0, 1) - al.addEdge(0, 4) - al.addEdge(4, 1) - al.addEdge(4, 3) - al.addEdge(1, 0) - al.addEdge(1, 4) - al.addEdge(1, 3) - al.addEdge(1, 2) - al.addEdge(2, 3) - al.addEdge(3, 4) - - al.printList() - - # OUTPUT: - # 0 -> 1 -> 4 - # 1 -> 0 -> 4 -> 3 -> 2 - # 2 -> 3 - # 3 -> 4 - # 4 -> 1 -> 3 diff --git a/graph algorithms/graph_list.py b/graph algorithms/graph_list.py deleted file mode 100644 index d67bc96c4a81..000000000000 --- a/graph algorithms/graph_list.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import print_function - - -class Graph: - def __init__(self, vertex): - self.vertex = vertex - self.graph = [[0] for i in range(vertex)] - - def add_edge(self, u, v): - self.graph[u - 1].append(v - 1) - - def show(self): - for i in range(self.vertex): - print('%d: '% (i + 1), end=' ') - for j in self.graph[i]: - print('%d-> '% (j + 1), end=' ') - print(' ') - - - -g = Graph(100) - -g.add_edge(1,3) -g.add_edge(2,3) -g.add_edge(3,4) -g.add_edge(3,5) -g.add_edge(4,5) - - -g.show() - diff --git a/graph algorithms/graph_matrix.py b/graph algorithms/graph_matrix.py deleted file mode 100644 index de25301d6dd1..000000000000 --- a/graph algorithms/graph_matrix.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import print_function - - -class Graph: - - def __init__(self, vertex): - self.vertex = vertex - self.graph = [[0] * vertex for i in range(vertex) ] - - def add_edge(self, u, v): - self.graph[u - 1][v - 1] = 1 - self.graph[v - 1][u - 1] = 1 - - def show(self): - - for i in self.graph: - for j in i: - print(j, end=' ') - print(' ') - - - - -g = Graph(100) - -g.add_edge(1,4) -g.add_edge(4,2) -g.add_edge(4,5) -g.add_edge(2,5) -g.add_edge(5,3) -g.show() - diff --git a/graph algorithms/kahns_algorithm_long.py b/graph algorithms/kahns_algorithm_long.py deleted file mode 100644 index 453b5706f6da..000000000000 --- a/graph algorithms/kahns_algorithm_long.py +++ /dev/null @@ -1,30 +0,0 @@ -# Finding longest distance in Directed Acyclic Graph using KahnsAlgorithm -def longestDistance(l): - indegree = [0] * len(l) - queue = [] - longDist = [1] * len(l) - - for key, values in l.items(): - for i in values: - indegree[i] += 1 - - for i in range(len(indegree)): - if indegree[i] == 0: - queue.append(i) - - while(queue): - vertex = queue.pop(0) - for x in l[vertex]: - indegree[x] -= 1 - - if longDist[vertex] + 1 > longDist[x]: - longDist[x] = longDist[vertex] + 1 - - if indegree[x] == 0: - queue.append(x) - - print(max(longDist)) - -# Adjacency list of Graph -l = {0:[2,3,4], 1:[2,7], 2:[5], 3:[5,7], 4:[7], 5:[6], 6:[7], 7:[]} -longestDistance(l) diff --git a/graph algorithms/kahns_algorithm_topo.py b/graph algorithms/kahns_algorithm_topo.py deleted file mode 100644 index 8c182c4e902c..000000000000 --- a/graph algorithms/kahns_algorithm_topo.py +++ /dev/null @@ -1,32 +0,0 @@ -# Kahn's Algorithm is used to find Topological ordering of Directed Acyclic Graph using BFS -def topologicalSort(l): - indegree = [0] * len(l) - queue = [] - topo = [] - cnt = 0 - - for key, values in l.items(): - for i in values: - indegree[i] += 1 - - for i in range(len(indegree)): - if indegree[i] == 0: - queue.append(i) - - while(queue): - vertex = queue.pop(0) - cnt += 1 - topo.append(vertex) - for x in l[vertex]: - indegree[x] -= 1 - if indegree[x] == 0: - queue.append(x) - - if cnt != len(l): - print("Cycle exists") - else: - print(topo) - -# Adjacency List of Graph -l = {0:[1,2], 1:[3], 2:[3], 3:[4,5], 4:[], 5:[]} -topologicalSort(l) diff --git a/graph algorithms/minimum_spanning_tree_kruskal.py b/graph algorithms/minimum_spanning_tree_kruskal.py deleted file mode 100644 index 81d64f421a31..000000000000 --- a/graph algorithms/minimum_spanning_tree_kruskal.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import print_function -num_nodes, num_edges = list(map(int,input().split())) - -edges = [] - -for i in range(num_edges): - node1, node2, cost = list(map(int,input().split())) - edges.append((i,node1,node2,cost)) - -edges = sorted(edges, key=lambda edge: edge[3]) - -parent = [i for i in range(num_nodes)] - -def find_parent(i): - if(i != parent[i]): - parent[i] = find_parent(parent[i]) - return parent[i] - -minimum_spanning_tree_cost = 0 -minimum_spanning_tree = [] - -for edge in edges: - parent_a = find_parent(edge[1]) - parent_b = find_parent(edge[2]) - if(parent_a != parent_b): - minimum_spanning_tree_cost += edge[3] - minimum_spanning_tree.append(edge) - parent[parent_a] = parent_b - -print(minimum_spanning_tree_cost) -for edge in minimum_spanning_tree: - print(edge) diff --git a/graph algorithms/minimum_spanning_tree_prims.py b/graph algorithms/minimum_spanning_tree_prims.py deleted file mode 100644 index 7b1ad0e743f7..000000000000 --- a/graph algorithms/minimum_spanning_tree_prims.py +++ /dev/null @@ -1,111 +0,0 @@ -import sys -from collections import defaultdict - -def PrimsAlgorithm(l): - - nodePosition = [] - def getPosition(vertex): - return nodePosition[vertex] - - def setPosition(vertex, pos): - nodePosition[vertex] = pos - - def topToBottom(heap, start, size, positions): - if start > size // 2 - 1: - return - else: - if 2 * start + 2 >= size: - m = 2 * start + 1 - else: - if heap[2 * start + 1] < heap[2 * start + 2]: - m = 2 * start + 1 - else: - m = 2 * start + 2 - if heap[m] < heap[start]: - temp, temp1 = heap[m], positions[m] - heap[m], positions[m] = heap[start], positions[start] - heap[start], positions[start] = temp, temp1 - - temp = getPosition(positions[m]) - setPosition(positions[m], getPosition(positions[start])) - setPosition(positions[start], temp) - - topToBottom(heap, m, size, positions) - - # Update function if value of any node in min-heap decreases - def bottomToTop(val, index, heap, position): - temp = position[index] - - while(index != 0): - if index % 2 == 0: - parent = int( (index-2) / 2 ) - else: - parent = int( (index-1) / 2 ) - - if val < heap[parent]: - heap[index] = heap[parent] - position[index] = position[parent] - setPosition(position[parent], index) - else: - heap[index] = val - position[index] = temp - setPosition(temp, index) - break - index = parent - else: - heap[0] = val - position[0] = temp - setPosition(temp, 0) - - def heapify(heap, positions): - start = len(heap) // 2 - 1 - for i in range(start, -1, -1): - topToBottom(heap, i, len(heap), positions) - - def deleteMinimum(heap, positions): - temp = positions[0] - heap[0] = sys.maxsize - topToBottom(heap, 0, len(heap), positions) - return temp - - visited = [0 for i in range(len(l))] - Nbr_TV = [-1 for i in range(len(l))] # Neighboring Tree Vertex of selected vertex - # Minimum Distance of explored vertex with neighboring vertex of partial tree formed in graph - Distance_TV = [] # Heap of Distance of vertices from their neighboring vertex - Positions = [] - - for x in range(len(l)): - p = sys.maxsize - Distance_TV.append(p) - Positions.append(x) - nodePosition.append(x) - - TreeEdges = [] - visited[0] = 1 - Distance_TV[0] = sys.maxsize - for x in l[0]: - Nbr_TV[ x[0] ] = 0 - Distance_TV[ x[0] ] = x[1] - heapify(Distance_TV, Positions) - - for i in range(1, len(l)): - vertex = deleteMinimum(Distance_TV, Positions) - if visited[vertex] == 0: - TreeEdges.append((Nbr_TV[vertex], vertex)) - visited[vertex] = 1 - for v in l[vertex]: - if visited[v[0]] == 0 and v[1] < Distance_TV[ getPosition(v[0]) ]: - Distance_TV[ getPosition(v[0]) ] = v[1] - bottomToTop(v[1], getPosition(v[0]), Distance_TV, Positions) - Nbr_TV[ v[0] ] = vertex - return TreeEdges - -# < --------- Prims Algorithm --------- > -n = int(input("Enter number of vertices: ")) -e = int(input("Enter number of edges: ")) -adjlist = defaultdict(list) -for x in range(e): - l = [int(x) for x in input().split()] - adjlist[l[0]].append([ l[1], l[2] ]) - adjlist[l[1]].append([ l[0], l[2] ]) -print(PrimsAlgorithm(adjlist)) diff --git a/graph algorithms/multi_hueristic_astar.py b/graph algorithms/multi_hueristic_astar.py deleted file mode 100644 index 1acd098f327d..000000000000 --- a/graph algorithms/multi_hueristic_astar.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import print_function -import heapq -import numpy as np - -try: - xrange # Python 2 -except NameError: - xrange = range # Python 3 - - -class PriorityQueue: - def __init__(self): - self.elements = [] - self.set = set() - - def minkey(self): - if not self.empty(): - return self.elements[0][0] - else: - return float('inf') - - def empty(self): - return len(self.elements) == 0 - - def put(self, item, priority): - if item not in self.set: - heapq.heappush(self.elements, (priority, item)) - self.set.add(item) - else: - # update - # print("update", item) - temp = [] - (pri, x) = heapq.heappop(self.elements) - while x != item: - temp.append((pri, x)) - (pri, x) = heapq.heappop(self.elements) - temp.append((priority, item)) - for (pro, xxx) in temp: - heapq.heappush(self.elements, (pro, xxx)) - - def remove_element(self, item): - if item in self.set: - self.set.remove(item) - temp = [] - (pro, x) = heapq.heappop(self.elements) - while x != item: - temp.append((pro, x)) - (pro, x) = heapq.heappop(self.elements) - for (prito, yyy) in temp: - heapq.heappush(self.elements, (prito, yyy)) - - def top_show(self): - return self.elements[0][1] - - def get(self): - (priority, item) = heapq.heappop(self.elements) - self.set.remove(item) - return (priority, item) - -def consistent_hueristic(P, goal): - # euclidean distance - a = np.array(P) - b = np.array(goal) - return np.linalg.norm(a - b) - -def hueristic_2(P, goal): - # integer division by time variable - return consistent_hueristic(P, goal) // t - -def hueristic_1(P, goal): - # manhattan distance - return abs(P[0] - goal[0]) + abs(P[1] - goal[1]) - -def key(start, i, goal, g_function): - ans = g_function[start] + W1 * hueristics[i](start, goal) - return ans - -def do_something(back_pointer, goal, start): - grid = np.chararray((n, n)) - for i in range(n): - for j in range(n): - grid[i][j] = '*' - - for i in range(n): - for j in range(n): - if (j, (n-1)-i) in blocks: - grid[i][j] = "#" - - grid[0][(n-1)] = "-" - x = back_pointer[goal] - while x != start: - (x_c, y_c) = x - # print(x) - grid[(n-1)-y_c][x_c] = "-" - x = back_pointer[x] - grid[(n-1)][0] = "-" - - - for i in xrange(n): - for j in range(n): - if (i, j) == (0, n-1): - print(grid[i][j], end=' ') - print("<-- End position", end=' ') - else: - print(grid[i][j], end=' ') - print() - print("^") - print("Start position") - print() - print("# is an obstacle") - print("- is the path taken by algorithm") - print("PATH TAKEN BY THE ALGORITHM IS:-") - x = back_pointer[goal] - while x != start: - print(x, end=' ') - x = back_pointer[x] - print(x) - quit() - -def valid(p): - if p[0] < 0 or p[0] > n-1: - return False - if p[1] < 0 or p[1] > n-1: - return False - return True - -def expand_state(s, j, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer): - for itera in range(n_hueristic): - open_list[itera].remove_element(s) - # print("s", s) - # print("j", j) - (x, y) = s - left = (x-1, y) - right = (x+1, y) - up = (x, y+1) - down = (x, y-1) - - for neighbours in [left, right, up, down]: - if neighbours not in blocks: - if valid(neighbours) and neighbours not in visited: - # print("neighbour", neighbours) - visited.add(neighbours) - back_pointer[neighbours] = -1 - g_function[neighbours] = float('inf') - - if valid(neighbours) and g_function[neighbours] > g_function[s] + 1: - g_function[neighbours] = g_function[s] + 1 - back_pointer[neighbours] = s - if neighbours not in close_list_anchor: - open_list[0].put(neighbours, key(neighbours, 0, goal, g_function)) - if neighbours not in close_list_inad: - for var in range(1,n_hueristic): - if key(neighbours, var, goal, g_function) <= W2 * key(neighbours, 0, goal, g_function): - # print("why not plssssssssss") - open_list[j].put(neighbours, key(neighbours, var, goal, g_function)) - - - # print - -def make_common_ground(): - some_list = [] - # block 1 - for x in range(1, 5): - for y in range(1, 6): - some_list.append((x, y)) - - # line - for x in range(15, 20): - some_list.append((x, 17)) - - # block 2 big - for x in range(10, 19): - for y in range(1, 15): - some_list.append((x, y)) - - # L block - for x in range(1, 4): - for y in range(12, 19): - some_list.append((x, y)) - for x in range(3, 13): - for y in range(16, 19): - some_list.append((x, y)) - return some_list - -hueristics = {0: consistent_hueristic, 1: hueristic_1, 2: hueristic_2} - -blocks_blk = [(0, 1),(1, 1),(2, 1),(3, 1),(4, 1),(5, 1),(6, 1),(7, 1),(8, 1),(9, 1),(10, 1),(11, 1),(12, 1),(13, 1),(14, 1),(15, 1),(16, 1),(17, 1),(18, 1), (19, 1)] -blocks_no = [] -blocks_all = make_common_ground() - - - - -blocks = blocks_blk -# hyper parameters -W1 = 1 -W2 = 1 -n = 20 -n_hueristic = 3 # one consistent and two other inconsistent - -# start and end destination -start = (0, 0) -goal = (n-1, n-1) - -t = 1 -def multi_a_star(start, goal, n_hueristic): - g_function = {start: 0, goal: float('inf')} - back_pointer = {start:-1, goal:-1} - open_list = [] - visited = set() - - for i in range(n_hueristic): - open_list.append(PriorityQueue()) - open_list[i].put(start, key(start, i, goal, g_function)) - - close_list_anchor = [] - close_list_inad = [] - while open_list[0].minkey() < float('inf'): - for i in range(1, n_hueristic): - # print("i", i) - # print(open_list[0].minkey(), open_list[i].minkey()) - if open_list[i].minkey() <= W2 * open_list[0].minkey(): - global t - t += 1 - # print("less prio") - if g_function[goal] <= open_list[i].minkey(): - if g_function[goal] < float('inf'): - do_something(back_pointer, goal, start) - else: - _, get_s = open_list[i].top_show() - visited.add(get_s) - expand_state(get_s, i, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer) - close_list_inad.append(get_s) - else: - # print("more prio") - if g_function[goal] <= open_list[0].minkey(): - if g_function[goal] < float('inf'): - do_something(back_pointer, goal, start) - else: - # print("hoolla") - get_s = open_list[0].top_show() - visited.add(get_s) - expand_state(get_s, 0, visited, g_function, close_list_anchor, close_list_inad, open_list, back_pointer) - close_list_anchor.append(get_s) - print("No path found to goal") - print() - for i in range(n-1,-1, -1): - for j in range(n): - if (j, i) in blocks: - print('#', end=' ') - elif (j, i) in back_pointer: - if (j, i) == (n-1, n-1): - print('*', end=' ') - else: - print('-', end=' ') - else: - print('*', end=' ') - if (j, i) == (n-1, n-1): - print('<-- End position', end=' ') - print() - print("^") - print("Start position") - print() - print("# is an obstacle") - print("- is the path taken by algorithm") -multi_a_star(start, goal, n_hueristic) diff --git a/graph algorithms/scc_kosaraju.py b/graph algorithms/scc_kosaraju.py deleted file mode 100644 index 1f13ebaba36b..000000000000 --- a/graph algorithms/scc_kosaraju.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import print_function -# n - no of nodes, m - no of edges -n, m = list(map(int,input().split())) - -g = [[] for i in range(n)] #graph -r = [[] for i in range(n)] #reversed graph -# input graph data (edges) -for i in range(m): - u, v = list(map(int,input().split())) - g[u].append(v) - r[v].append(u) - -stack = [] -visit = [False]*n -scc = [] -component = [] - -def dfs(u): - global g, r, scc, component, visit, stack - if visit[u]: return - visit[u] = True - for v in g[u]: - dfs(v) - stack.append(u) - -def dfs2(u): - global g, r, scc, component, visit, stack - if visit[u]: return - visit[u] = True - component.append(u) - for v in r[u]: - dfs2(v) - -def kosaraju(): - global g, r, scc, component, visit, stack - for i in range(n): - dfs(i) - visit = [False]*n - for i in stack[::-1]: - if visit[i]: continue - component = [] - dfs2(i) - scc.append(component) - return scc - -print(kosaraju()) diff --git a/graph algorithms/tarjans_scc.py b/graph algorithms/tarjans_scc.py deleted file mode 100644 index 89754e593508..000000000000 --- a/graph algorithms/tarjans_scc.py +++ /dev/null @@ -1,78 +0,0 @@ -from collections import deque - - -def tarjan(g): - """ - Tarjan's algo for finding strongly connected components in a directed graph - - Uses two main attributes of each node to track reachability, the index of that node within a component(index), - and the lowest index reachable from that node(lowlink). - - We then perform a dfs of the each component making sure to update these parameters for each node and saving the - nodes we visit on the way. - - If ever we find that the lowest reachable node from a current node is equal to the index of the current node then it - must be the root of a strongly connected component and so we save it and it's equireachable vertices as a strongly - connected component. - - Complexity: strong_connect() is called at most once for each node and has a complexity of O(|E|) as it is DFS. - Therefore this has complexity O(|V| + |E|) for a graph G = (V, E) - - """ - - n = len(g) - stack = deque() - on_stack = [False for _ in range(n)] - index_of = [-1 for _ in range(n)] - lowlink_of = index_of[:] - - def strong_connect(v, index, components): - index_of[v] = index # the number when this node is seen - lowlink_of[v] = index # lowest rank node reachable from here - index += 1 - stack.append(v) - on_stack[v] = True - - for w in g[v]: - if index_of[w] == -1: - index = strong_connect(w, index, components) - lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] - elif on_stack[w]: - lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] - - if lowlink_of[v] == index_of[v]: - component = [] - w = stack.pop() - on_stack[w] = False - component.append(w) - while w != v: - w = stack.pop() - on_stack[w] = False - component.append(w) - components.append(component) - return index - - components = [] - for v in range(n): - if index_of[v] == -1: - strong_connect(v, 0, components) - - return components - - -def create_graph(n, edges): - g = [[] for _ in range(n)] - for u, v in edges: - g[u].append(v) - return g - - -if __name__ == '__main__': - # Test - n_vertices = 7 - source = [0, 0, 1, 2, 3, 3, 4, 4, 6] - target = [1, 3, 2, 0, 1, 4, 5, 6, 5] - edges = [(u, v) for u, v in zip(source, target)] - g = create_graph(n_vertices, edges) - - assert [[5], [6], [4], [3, 2, 1, 0]] == tarjan(g) From 296ad877fd3e92eba852a493a317b66fea537b64 Mon Sep 17 00:00:00 2001 From: John Law Date: Mon, 25 Feb 2019 17:33:57 +0800 Subject: [PATCH 4/4] Rename number theory/factorial_python.py to maths/factorial_python.py --- {number theory => maths}/factorial_python.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {number theory => maths}/factorial_python.py (100%) diff --git a/number theory/factorial_python.py b/maths/factorial_python.py similarity index 100% rename from number theory/factorial_python.py rename to maths/factorial_python.py