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

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

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

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

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

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

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

Вершины графа могут быть пронумерованы не подряд. $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

Для приведённого примера при условии «ровно из $2$ рёбер» верным ответом будет $2$ (пути $1–7–100$ и $1–4–100$); путь ровно из одного ребра один ($1–100$), путей из трёх и более рёбер нет.

У функции появляется второй параметр — сколько рёбер ещё нужно пройти: $f(v, k)$ — число путей из $v$ в $100$ ровно из $k$ рёбер. База: при $k = 0$ путь завершён и годится только если мы стоим в $100$. Переход: $f(v, k) = Σ f(u, k − 1)$ по рёбрам $v → u$. Запоминание работает по паре ($v, k$). Веса не нужны.

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

Для справки — распределение путей $1 → 100$ по числу рёбер в этом файле: $4$ ребра — $4$ пути, $5 — 30$, $6 — 206$, $7 — 1007$, $8 — 4224$, $9 — 15003$, $10 — 45801, … , 27 — 240$; всего $17 270 047$ путей.

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

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