Программа курса:
Разбор задачи: Задержка сигнала в сети
Предложенный нами код решения:
from heapq import heappush, heappop
from collections import defaultdict
def network_delay_time(times, n, k):
# Построение графа
graph = defaultdict(list)
for u, v, w in times:
graph[u].append((v, w))
# Инициализация структуры для хранения времени
min_heap = [(0, k)] # (время, узел)
visited = {}
while min_heap:
time, node = heappop(min_heap)
if node in visited:
continue
visited[node] = time
for neighbor, weight in graph[node]:
if neighbor not in visited:
heappush(min_heap, (time + weight, neighbor))
if len(visited) == n:
return max(visited.values())
return -1
Построение графа
Изначально из входного списка times создаётся граф, представленный как словарь смежностей. Каждый узел указывает на список соседей с указанием времени передачи сигнала.
graph = defaultdict(list)
for u, v, w in times:
graph[u].append((v, w))
Пример: для times = [[2, 1, 1], [2, 3, 1], [3, 4, 1]] граф выглядит так:
Граф:
2 -> (1, 1), (3, 1)
3 -> (4, 1)
Схема графа:
2
/ \
(1) (1)
/ \
1 3
\
(1)
\
4
Здесь числа в скобках — время передачи сигнала.
Инициализация
min_heap = [(0, k)] # (время, узел)
visited = {}
Очередь с приоритетом min_heap изначально содержит начальный узел k с временем 0. Словарь visited пуст, так как ни один узел ещё не обработан.
Пример для k = 2:
min_heap = [(0, 2)] # Начинаем с узла 2
visited = {}
Обработка узлов
Алгоритм работает в цикле, извлекая узел с минимальным временем из min_heap.
Шаг 1: Извлечение начального узла
time, node = heappop(min_heap)
if node in visited:
continue
visited[node] = time
Для первого шага:
Извлекаем: (0, 2)
Добавляем в visited: {2: 0}
Шаг 2: Обработка соседей узла 2
for neighbor, weight in graph[node]:
if neighbor not in visited:
heappush(min_heap, (time + weight, neighbor))
Соседи узла 2:
- Узел
1с временем1. - Узел
3с временем1.
Очередь обновляется:
min_heap = [(1, 1), (1, 3)]
Визуализация пробега
На каждом шаге узлы извлекаются из очереди и обрабатываются. Визуализируем:
- Изначально:
min_heap: [(0, 2)]
visited: {}
- Шаг 1: обработка узла 2:
Извлечено: (0, 2)
Добавлено в visited: {2: 0}
min_heap: [(1, 1), (1, 3)]
Граф после обработки:
2 [обработан]
/ \
(1) (1)
/ \
1 3
\
(1)
\
4
- Шаг 2: обработка узла 1:
Извлечено: (1, 1)
Добавлено в visited: {2: 0, 1: 1}
min_heap: [(1, 3)]
Узел 1 не имеет соседей, изменений в очереди нет.
- Шаг 3: обработка узла 3:
Извлечено: (1, 3)
Добавлено в visited: {2: 0, 1: 1, 3: 1}
min_heap: [(2, 4)]
Граф:
2 [обработан]
/ \
(1) (1)
/ \
1 3 [обработан]
\
(1)
\
4
- Шаг 4: обработка узла 4:
Извлечено: (2, 4)
Добавлено в visited: {2: 0, 1: 1, 3: 1, 4: 2}
min_heap: []
Граф:
2 [обработан]
/ \
(1) (1)
/ \
1 3 [обработан]
\
(1)
\
4 [обработан]
Проверка достижимости
После завершения цикла проверяется, обработаны ли все узлы:
if len(visited) == n:
return max(visited.values())
return -1
Пример:
- Если
visited = {2: 0, 1: 1, 3: 1, 4: 2}иn = 4, то результат:max(visited.values()) = 2. - Если
visited = {1: 0, 2: 1}иn = 3, то возвращается-1.