🎯 DFS-based Topological Sort
                    
                    
                        DFS Algorithm
                        Uses post-order traversal with a stack to build the topological order.
                        
                            - 🔍 Visit each unvisited vertex
 
                            - 📚 Recursively visit all neighbors
 
                            - 🎯 Add vertex to stack after visiting all neighbors
 
                            - ↩️ Reverse the stack for final order
 
                        
                     
                    Implementation with Cycle Detection
                    
def topological_sort_dfs(vertices, edges):
    """
    DFS-based topological sorting
    Time: O(V + E), Space: O(V)
    """
    # Build adjacency list
    graph = defaultdict(list)
    for u, v in edges:
        graph[u].append(v)
    
    # Color states: WHITE (0) = unvisited, GRAY (1) = visiting, BLACK (2) = visited
    color = {v: 0 for v in vertices}
    stack = []
    has_cycle = False
    
    def dfs(vertex):
        nonlocal has_cycle
        if has_cycle:
            return
        
        color[vertex] = 1  # Mark as visiting (GRAY)
        
        for neighbor in graph[vertex]:
            if color[neighbor] == 1:  # Back edge (cycle detected)
                has_cycle = True
                return
            elif color[neighbor] == 0:  # Unvisited
                dfs(neighbor)
        
        color[vertex] = 2  # Mark as visited (BLACK)
        stack.append(vertex)  # Add to stack in post-order
    
    # Visit all vertices
    for vertex in vertices:
        if color[vertex] == 0:
            dfs(vertex)
    
    if has_cycle:
        return None  # Cycle detected
    
    return stack[::-1]  # Reverse for topological order
# Example with cycle detection
vertices = ['A', 'B', 'C', 'D']
edges = [('A', 'B'), ('B', 'C'), ('C', 'D')]
print(topological_sort_dfs(vertices, edges))
# Output: ['A', 'B', 'C', 'D']
# Example with cycle
edges_with_cycle = [('A', 'B'), ('B', 'C'), ('C', 'A')]
print(topological_sort_dfs(['A', 'B', 'C'], edges_with_cycle))
# Output: None (cycle detected)
                    All Topological Sorts
                    
def all_topological_sorts(vertices, edges):
    """
    Generate all possible topological sorts
    """
    graph = defaultdict(list)
    in_degree = {v: 0 for v in vertices}
    
    for u, v in edges:
        graph[u].append(v)
        in_degree[v] += 1
    
    all_sorts = []
    
    def backtrack(current_sort, remaining):
        if not remaining:
            all_sorts.append(current_sort[:])
            return
        
        # Try each vertex with in-degree 0
        for vertex in remaining:
            if in_degree[vertex] == 0:
                # Choose vertex
                current_sort.append(vertex)
                new_remaining = remaining - {vertex}
                
                # Update in-degrees
                for neighbor in graph[vertex]:
                    in_degree[neighbor] -= 1
                
                # Recurse
                backtrack(current_sort, new_remaining)
                
                # Backtrack
                for neighbor in graph[vertex]:
                    in_degree[neighbor] += 1
                current_sort.pop()
    
    backtrack([], set(vertices))
    return all_sorts
# Example
vertices = ['A', 'B', 'C']
edges = [('A', 'C')]
print(all_topological_sorts(vertices, edges))
# Output: [['A', 'B', 'C'], ['B', 'A', 'C']]