Новости IT, Tech-лайфхаки & Кодинг

Решение задачи #10. Python CodeRun, Топологическая сортировка

Вариант решения задачи на языке программирования Python с Яндекс CodeRun.
Категория: Алгоритмы.
Название задачи: Топологическая сортировка.
Сложность: Лёгкая.
Статус решения: "Решено".


Условие задачи:
Дан ориентированный граф. Необходимо построить топологическую сортировку.

Напомним: Топологическая сортировка указывает такой линейный порядок на его вершинах, что любое ребро ведёт от вершины с меньшим номером к вершине с большим номером.
Формат ввода

В первой строке входного файла два натуральных числа NN и MM (1≤N,M≤100 000)(1≤N,M≤100000) — количество вершин и рёбер в графе соответственно. Далее в MM строках перечислены рёбра графа. Каждое ребро задаётся парой чисел — номерами начальной и конечной вершин соответственно.

Формат вывода:
Выведите любую топологическую сортировку графа в виде последовательности номеров вершин (перестановка чисел от 1 до N). Если топологическую сортировку графа построить невозможно, выведите -1.

Примечание:
Если отбросить формализм, то можно сказать, что нужно сделать следующее: перенумеровать все вершины нашего графа.

Для всех M рёбер из входных данных и только для них должно выполняться условие, что ребро ведёт из вершины с меньшим номером в вершину с большим номером.

Решение:


Python

from collections import defaultdict, deque

def topological_sort(n, edges):
    """
    Функция для выполнения топологической сортировки графа.
    :param n: количество вершин в графе
    :param edges: список рёбер графа (список кортежей (u, v), где u -> v)
    :return: список вершин в порядке топологической сортировки или -1, если сортировка невозможна
    """
    # Инициализируем граф и массив для подсчёта входящих степеней
    graph = defaultdict(list)
    in_degree = [0] * (n + 1)

    # Строим граф и подсчитываем входящие степени
    for u, v in edges:
        graph[u].append(v)
        in_degree[v] += 1

    # Ищем все вершины с нулевой входящей степенью (можно начинать с них)
    queue = deque([i for i in range(1, n + 1) if in_degree[i] == 0])

    # Список для хранения результата топологической сортировки
    topo_order = []

    # Алгоритм Кана
    while queue:
        # Извлекаем вершину с нулевой входящей степенью
        current = queue.popleft()
        topo_order.append(current)

        # Уменьшаем входящую степень всех соседей текущей вершины
        for neighbor in graph[current]:
            in_degree[neighbor] -= 1
            # Если входящая степень соседа стала равна нулю, добавляем его в очередь
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    # Если мы обошли все вершины, возвращаем порядок
    if len(topo_order) == n:
        return topo_order
    else:
        # Если остались вершины с ненулевой входящей степенью, граф содержит цикл
        return -1

# Ввод данных
if __name__ == "__main__":
    import sys
    input = sys.stdin.read
    data = input().split()
    
    n, m = int(data[0]), int(data[1])  # Читаем количество вершин и рёбер
    edges = []
    for i in range(m):
        u, v = int(data[2 + i * 2]), int(data[3 + i * 2])
        edges.append((u, v))
    
    # Вызываем функцию топологической сортировки и выводим результат
    result = topological_sort(n, edges)
    if result == -1:
        print(-1)
    else:
        print(" ".join(map(str, result)))

Объяснение кода

Инициализация данных:
Читаем количество вершин N и рёбер M. Формируем список рёбер графа.

Построение графа:
Используем defaultdict для представления графа в виде списка смежности. Одновременно подсчитываем количество входящих рёбер для каждой вершины (массив in_degree).

Поиск начальных вершин:
Все вершины с нулевой входящей степенью добавляем в очередь deque.

Алгоритм Кана:
Пока очередь не пуста:
Извлекаем вершину из очереди и добавляем её в итоговый порядок (topo_order).
Для всех её соседей уменьшаем входящую степень. Если входящая степень соседа становится равна нулю, добавляем его в очередь. Этот процесс продолжается, пока мы не обработаем все вершины.

Проверка результата:
Если количество обработанных вершин (len(topo_order)) меньше N, значит в графе есть цикл, и топологическая сортировка невозможна. В противном случае возвращаем итоговый порядок.

Вывод результата:
Если сортировка возможна, выводим порядок вершин.
Если нет, выводим -1.

Источник решения: hdhAI.com

Добавьте Hdhai в избранное и вы будете чаще видеть наши последние новости на главной Дзена и в разделе «Новости партнёров» или читайте нас в Telegram в привычном для вас формате.