from collections import defaultdict
from collections import deque
class Graph:
def __init__(self, nodes):
self.nodes = nodes
self.neighbours = defaultdict(list)
def addDirectedEdge(self, u, v):
self.neighbours[u].append(v)
def addUndirectedEdge(self, u, v):
self.neighbours[u].append(v)
self.neighbours[v].append(u)
def addTransposeEdge(self, u, v):
self.neighbours[v].append(u)
def deleteNodes(self, *nodes):
for node in nodes:
del self.neighbours[node]
self.nodes -= 1
return self
def transpose(self):
if self.nodes > 0:
transposed_graph = defaultdict(list)
for source, targets in self.neighbours.items():
for target in targets:
transposed_graph[target].append(source)
t = Graph(self.nodes)
t.neighbours = transposed_graph
return t
else:
return None
def bfs(self, source):
visited = {i: False for i in range(1, self.node + 1)}
queue = []
queue.append(source)
visited[source] = True
while queue:
source = queue.pop(0)
print(source, sep=' ')
for i in self.neighbours[source]:
if not visited[i]:
queue.append(i)
visited[i] = True
def bfs_cost(self, source):
visited = {i: False for i in range(1, self.nodes + 1)}
queue = []
cost = {i: 0 for i in range(1, self.nodes + 1)}
queue.append(source)
visited[source] = True
while queue:
source = queue.pop(0)
print(source, sep=' ')
for i in self.neighbours[source]:
if not visited[i]:
queue.append(i)
cost[i] = cost[source] + 1
visited[i] = True
for node in self.neighbours.keys():
if not visited[node]:
cost[node] = -1
return cost
def dfs(self, source, visited):
visited[source] = True
for i in self.neighbours[source]:
if not visited[i]:
self.dfs(i, visited)
return visited
def numberOfConnectedComponents(self):
visited = {i: False for i in range(1, self.nodes + 1)}
count = 0
for node in range(1, self.nodes + 1):
if not visited[node]:
self.dfs(node, visited)
count += 1
return count
def dfs_Kosaraju1(self, source, visited, stack):
visited[source] = True
for node in self.neighbours[source]:
if not visited[node]:
self.dfs_Kosaraju1(node, visited, stack)
stack.append(source)
def dfs_Kosaraju2(self, source, visited, components, count):
visited[source] = True
components[count].append(source)
transpose_g = self.transpose()
for node in transpose_g.neighbours[source]:
if not visited[node]:
self.dfs_Kosaraju2(node, visited, components, count)
def SCC_Kosaraju(self):
stack = deque()
components = defaultdict(list)
count = 0
visited = {i: False for i in range(1, self.nodes + 1)}
for node in list(self.neighbours.keys()):
if not visited[node]:
self.dfs_Kosaraju1(node, visited, stack)
visited = {i: False for i in range(1, self.nodes + 1)}
while stack:
node = stack.pop()
if not visited[node]:
count += 1
self.dfs_Kosaraju2(node, visited, components, count)
return components
def topoSortDFS(self, soruce, visited, stack):
visited[soruce] = True
for neighbour in self.neighbours[soruce]:
if not visited[neighbour]:
self.topoSortDFS(neighbour, visited, stack)
stack.append(soruce)
def topologicalSort(self):
stack = deque()
result = []
visited = {i: False for i in range(1, self.nodes + 1)}
for node in list(self.neighbours.keys()):
if not visited[node]:
self.topoSortDFS(node, visited, stack)
while stack:
node = stack.pop()
result.append(node)
return result
# # STRONGLY CONNECTED COMPONENTS
# file_ctc = 'ctc.in'
#
# with open(file_ctc, 'rt') as f:
# content = f.readlines()
# content = [line.strip().split() for line in content]
# content = [[int(x) for x in line] for line in content]
# N, M = content[0][0], content[0][1]
#
#
# g = Graph(N)
# for edges in content[1:]:
# g.addDirectedEdge(edges[0], edges[1])
#
# visited = {i: False for i in range(1, g.nodes + 1)}
# result = g.SCC_Kosaraju()
#
# with open('ctc.out', 'wt') as f:
# f.write(str(len(result.keys())))
# f.write('\n')
# for component in result.values():
# for node in component:
# f.write(str(node))
# f.write(' ')
# f.write('\n')
# TOPOLOGICAL SORT
file_sortaret = 'sortaret.in'
with open(file_sortaret, 'rt') as f:
content = f.readlines()
content = [line.strip().split() for line in content]
content = [[int(x) for x in line] for line in content]
N, M = content[0][0], content[0][1]
g = Graph(N)
for edges in content[1:]:
g.addDirectedEdge(edges[0], edges[1])
visited = {i: False for i in range(1, N + 1)}
result = g.topologicalSort()
with open('sortaret.out', 'wt') as f:
for node in result:
f.write(str(node))
f.write(' ')
## NUMBER OF CONNECTED COMPONENTS
# file_dfs = 'dfs.in'
#
# with open(file_dfs, 'rt') as f:
# content = f.readlines()
# content = [line.strip().split() for line in content]
# content = [[int(x) for x in line] for line in content]
# N, M = content[0][0], content[0][1]
#
# g = Graph(N)
# for edges in content[1:]:
# g.addUndirectedEdge(edges[0], edges[1])
#
# result = g.numberOfConnectedComponents()
#
# with open('dfs.out', 'wt') as f:
# f.write(str(result))