Some directories had a capital in their name [fixed]. Added a recursive factorial algorithm. (#763)

* Renaming directories
* Adding a recursive factorial algorithm
This commit is contained in:
Vysor
2019-04-23 00:53:56 +10:00
committed by John Law
parent 48bba495ae
commit df04d94543
36 changed files with 13 additions and 0 deletions

39
graphs/BFS.py Normal file
View File

@@ -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'))

36
graphs/DFS.py Normal file
View File

@@ -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'))

View File

@@ -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

102
graphs/a_star.py Normal file
View File

@@ -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])

View File

@@ -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)

290
graphs/basic_graphs.py Normal file
View File

@@ -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

54
graphs/bellman_ford.py Normal file
View File

@@ -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)

View File

@@ -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

View File

@@ -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))

View File

@@ -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

47
graphs/dijkstra.py Normal file
View File

@@ -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)

57
graphs/dijkstra_2.py Normal file
View File

@@ -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)

View File

@@ -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

70
graphs/even_tree.py Normal file
View File

@@ -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)

31
graphs/finding_bridges.py Normal file
View File

@@ -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)

48
graphs/floyd_warshall.py Normal file
View File

@@ -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)

44
graphs/graph.py Normal file
View File

@@ -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

31
graphs/graph_list.py Normal file
View File

@@ -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()

32
graphs/graph_matrix.py Normal file
View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)

46
graphs/scc_kosaraju.py Normal file
View File

@@ -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())

78
graphs/tarjans_scc.py Normal file
View File

@@ -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)