Topological Sort

A directed acyclic graph (DAG) represents task ordering, with tasks as vertices and task constraints as edges. Topological sort provides the proper task sequence. Given a DAG G, print the vertex order after topological sort.

Input
A directed graph G is given as:
|V| |E|
s0 t0
s1 t1
...
s(|E|-1) t(|E|-1)

|V| is the number of vertices, |E| is the number of edges, and vertices are named 0 to |V|-1. si and ti represent source and target nodes of the i-th edge.

Output
Print the vertex numbers in order, one per line. If multiple solutions exist, any one is acceptable.

Constraints
- 1 ≤ |V| ≤ 10,000
- 0 ≤ |E| ≤ 100,000
- No parallel edges or self-loops in G

Sample Input
6 6
0 1
1 2
3 1
3 4
4 5
5 2

Sample Output
0
3
1
4
5
2

# Buggy version:
from collections import deque, defaultdict

def topological_sort(V, E):
    '''
    Kahn's Algorithm (O(|V| + |E|) time)
    Input:
    V = [0, 1, ..., N-1]: a list of vertices of the digraph
    E: the adjacency list of the digraph (dict)
    Output:
    If the input digraph is acyclic, then return a topological sorting of the digraph.
    Else, return None.
    '''
    indeg = {v: 0 for v in V}
    for ends in E.values():
        for v in ends:
            indeg[v] += 1
    
    q = deque([v for v in V if indeg[v] == 0])
    top_sorted = []
    while q:
        v = q.popleft()
        top_sorted.append(v)
        
        for u in E[v]:
            indeg[u] -= 1
            if indeg[u] == 0:
                q.append(u)
    if len(top_sorted) == len(V): # The input digraph is acyclic.
        return top_sorted
    else: # There is a directed cycle in the digraph.
        return None

N, M = map(int, input().split())
E = defaultdict(list)
for _ in range(M):
    s, t = map(int, input().split())
    E[s].append(t)
print(*topological_sort(V, E), sep='\n')


# Fixed version:
from collections import deque, defaultdict

def topological_sort(V, E):
    '''
    Kahn's Algorithm (O(|V| + |E|) time)
    Input:
    V = [0, 1, ..., N-1]: a list of vertices of the digraph
    E: the adjacency list of the digraph (dict)
    Output:
    If the input digraph is acyclic, then return a topological sorting of the digraph.
    Else, return None.
    '''
    indeg = {v: 0 for v in V}
    for ends in E.values():
        for v in ends:
            indeg[v] += 1
    
    q = deque([v for v in V if indeg[v] == 0])
    top_sorted = []
    while q:
        v = q.popleft()
        top_sorted.append(v)
        
        for u in E[v]:
            indeg[u] -= 1
            if indeg[u] == 0:
                q.append(u)
    if len(top_sorted) == len(V): # The input digraph is acyclic.
        return top_sorted
    else: # There is a directed cycle in the digraph.
        return None

N, M = map(int, input().split())
V = range(N)
E = defaultdict(list)
for _ in range(M):
    s, t = map(int, input().split())
    E[s].append(t)
print(*topological_sort(V, E), sep='\n')

# Buggy version:
# -*- coding: utf-8 -*-

import sys
import os
import pprint
from queue import Queue

"""Topological Sort"""

#fd = os.open('GRL_4_B.txt', os.O_RDONLY)
#os.dup2(fd, sys.stdin.fileno())

V, E = list(map(int, input().split()))
G = [[] for i in range(V)]
indig = [0] * V # ??\?¬???°
for i in range(V):
    s, t = list(map(int, input().split()))
    G[s].append(t)
    indig[t] += 1

q = Queue()
out = []

def bfs(node_index):
    q.put(node_index)

    while not q.empty():
        u = q.get()
        out.append(u)

        # u?????????????????§u?????????indig????????????
        for index in G[u]:
            indig[index] -= 1
            if indig[index] == 0:
                q.put(index)

# bfs?????????
indig_copy = indig[:]
for i in range(V):
    if indig_copy[i] == 0:
        bfs(node_index=i)


print(out)

# Fixed version:
# -*- coding: utf-8 -*-

import sys
import os
import pprint
from queue import Queue

"""Topological Sort"""

#fd = os.open('GRL_4_B_5.txt', os.O_RDONLY)
#os.dup2(fd, sys.stdin.fileno())

V, E = list(map(int, input().split()))
G = [[] for i in range(V)]
indig = [0] * V # ??\?¬???°
for i in range(E):
    s, t = list(map(int, input().split()))
    G[s].append(t)
    indig[t] += 1

q = Queue()
out = []

def bfs(node_index):
    q.put(node_index)

    while not q.empty():
        u = q.get()
        out.append(u)

        # u?????????????????§u?????????indig????????????
        for index in G[u]:
            indig[index] -= 1
            if indig[index] == 0:
                q.put(index)

# bfs?????????
indig_copy = indig[:]
for i in range(V):
    if indig_copy[i] == 0:
        bfs(node_index=i)

for v in out:
    print(v)