Подготовка к школе
1 класс
2 класс
3 класс
4 класс
5 класс
6 класс
7 класс
8 класс
9 класс
10 класс
11 класс
ОГЭ
ЕГЭ
Для всех
Назад

23. Алгоритмические задачи, связанные с анализом графов: #313151

Сообщить о проблеме
Задание #313151
Задание было решено верно
Задание было решено неверно

В текстовом файле содержится описание ациклического ориентированного взвешенного графа.

В каждой строке файла записаны два натуральных числа ($L, M$) и одно положительное вещественное число ($W$). $L, M$  — номера вершин графа, $W$  — вес ребра, ведущего из вершины $L$ в вершину $M$. Таким образом, количество строк в файле равно количеству рёбер в графе. Две вершины графа не могут быть соединены более чем одним ребром.

Найдите и запишите в ответе наименьшее количество рёбер, из которых может состоять путь из вершины с номером $1$ в вершину с номером $100$. Существование хотя бы одного такого пути гарантируется.

Для выполнения этого задания следует написать программу.

Вершины графа могут быть пронумерованы не подряд. $L ≤ 1000, M ≤ 1000; W ≤ 10 000$. Количество строк в файле не превосходит $200$. Числа в строках разделены произвольным ненулевым количеством пробелов и/или табуляций.

Типовой пример организации данных во входном файле для графа на рисунке

100
6
6
1
7
4
1
1
12
7
1
7
100
100
100
4
1.0
7.0
1.0
5.5
2.0
8.0
12.0
2.5

Для приведённого примера верным ответом будет $1$: путь $1–100$ состоит из одного ребра (веса рёбер в этом вопросе не учитываются).

Это кратчайший путь в графе, где каждое ребро весит $1$: веса из файла не читаются, а в переходе вместо $w + f(u)$ стоит $1 + f(u)$. Второй способ — поиск в ширину: при обходе по слоям первое посещение вершины происходит по пути с наименьшим числом рёбер.

from functools import lru_cache
import sys
sys.setrecursionlimit(10000)
g = {}                                   # вершина -> список соседей
for line in open('23_15.txt'):
    s = line.split()
    if len(s) < 3:
        continue
    a, b = int(s[0]), int(s[1])          # вес ребра не нужен
    g.setdefault(a, []).append(b)
@lru_cache(None)
def f(v):                                # наименьшее число рёбер v -> 100
    if v == 100:
        return 0
    best = float('inf')
    for u in g.get(v, []):
        best = min(best, 1 + f(u))       # каждое ребро «весит» 1
    return best
print(f(1))

Второй способ — поиск в ширину (продолжение после чтения графа):

from collections import deque
dist = {1: 0}                            # поиск в ширину из вершины 1
q = deque([1])
while q:
    v = q.popleft()
    for u in g.get(v, []):
        if u not in dist:                # первое посещение — кратчайшее
            dist[u] = dist[v] + 1
            q.append(u)
print(dist[100])

Путей из пяти рёбер в этом файле пять (совпадение с ответом случайно). Кратчайший по сумме весов путь (длина $12607,9$) состоит из $6$ рёбер, самый длинный по числу рёбер путь — из $26$.

Показать
Очки опыта 20
Спросить Зави
0 заданий сегодня

Предложить улучшение