diff --git a/Graphs/ArticulationPoints.py b/Graphs/ArticulationPoints.py new file mode 100644 index 000000000..9965f5cb2 --- /dev/null +++ b/Graphs/ArticulationPoints.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, end=" ") + +# 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/CheckBipartiteGraph_BFS.py b/Graphs/CheckBipartiteGraph_BFS.py new file mode 100644 index 000000000..1b9c32c6c --- /dev/null +++ b/Graphs/CheckBipartiteGraph_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/FindingBridges.py b/Graphs/FindingBridges.py new file mode 100644 index 000000000..56533dd48 --- /dev/null +++ b/Graphs/FindingBridges.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/KahnsAlgorithm_long.py b/Graphs/KahnsAlgorithm_long.py new file mode 100644 index 000000000..453b5706f --- /dev/null +++ b/Graphs/KahnsAlgorithm_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/KahnsAlgorithm_topo.py b/Graphs/KahnsAlgorithm_topo.py new file mode 100644 index 000000000..8c182c4e9 --- /dev/null +++ b/Graphs/KahnsAlgorithm_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/MinimumSpanningTree_Prims.py b/Graphs/MinimumSpanningTree_Prims.py new file mode 100644 index 000000000..7b1ad0e74 --- /dev/null +++ b/Graphs/MinimumSpanningTree_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/Maths/BasicMaths.py b/Maths/BasicMaths.py new file mode 100644 index 000000000..f05cde64d --- /dev/null +++ b/Maths/BasicMaths.py @@ -0,0 +1,70 @@ +import math + +def primeFactors(n): + pf = [] + while n % 2 == 0: + pf.append(2) + n = int(n / 2) + + for i in range(3, int(math.sqrt(n))+1, 2): + while n % i == 0: + pf.append(i) + n = int(n / i) + + if n > 2: + pf.append(n) + + return pf + +def numberOfDivisors(n): + div = 1 + + temp = 1 + while n % 2 == 0: + temp += 1 + n = int(n / 2) + div = div * (temp) + + for i in range(3, int(math.sqrt(n))+1, 2): + temp = 1 + while n % i == 0: + temp += 1 + n = int(n / i) + div = div * (temp) + + return div + +def sumOfDivisors(n): + s = 1 + + temp = 1 + while n % 2 == 0: + temp += 1 + n = int(n / 2) + if temp > 1: + s *= (2**temp - 1) / (2 - 1) + + for i in range(3, int(math.sqrt(n))+1, 2): + temp = 1 + while n % i == 0: + temp += 1 + n = int(n / i) + if temp > 1: + s *= (i**temp - 1) / (i - 1) + + return s + +def eulerPhi(n): + l = primeFactors(n) + l = set(l) + s = n + for x in l: + s *= (x - 1)/x + return s + +print(primeFactors(100)) +print(numberOfDivisors(100)) +print(sumOfDivisors(100)) +print(eulerPhi(100)) + + \ No newline at end of file diff --git a/Maths/SegmentedSieve.py b/Maths/SegmentedSieve.py new file mode 100644 index 000000000..52ca6fbe6 --- /dev/null +++ b/Maths/SegmentedSieve.py @@ -0,0 +1,46 @@ +import math + +def sieve(n): + in_prime = [] + start = 2 + end = int(math.sqrt(n)) # Size of every segment + temp = [True] * (end + 1) + prime = [] + + while(start <= end): + if temp[start] == True: + in_prime.append(start) + for i in range(start*start, end+1, start): + if temp[i] == True: + temp[i] = False + start += 1 + prime += in_prime + + low = end + 1 + high = low + end - 1 + if high > n: + high = n + + while(low <= n): + temp = [True] * (high-low+1) + for each in in_prime: + + t = math.floor(low / each) * each + if t < low: + t += each + + for j in range(t, high+1, each): + temp[j - low] = False + + for j in range(len(temp)): + if temp[j] == True: + prime.append(j+low) + + low = high + 1 + high = low + end - 1 + if high > n: + high = n + + return prime + +print(sieve(10**6)) \ No newline at end of file diff --git a/Maths/SieveOfEratosthenes.py b/Maths/SieveOfEratosthenes.py new file mode 100644 index 000000000..bac4341de --- /dev/null +++ b/Maths/SieveOfEratosthenes.py @@ -0,0 +1,24 @@ +import math +n = int(input("Enter n: ")) + +def sieve(n): + l = [True] * (n+1) + prime = [] + start = 2 + end = int(math.sqrt(n)) + while(start <= end): + if l[start] == True: + prime.append(start) + for i in range(start*start, n+1, start): + if l[i] == True: + l[i] = False + start += 1 + + for j in range(end+1,n+1): + if l[j] == True: + prime.append(j) + + return prime + +print(sieve(n)) + \ No newline at end of file