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

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

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

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

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

Найдите и запишите в ответе наибольшее количество различных путей между какой-либо парой вершин графа, то есть максимум по всем парам различных вершин ($A, B$) числа различных путей из вершины $A$ в вершину $B$. Два пути считаются различными, если они отличаются хотя бы одним ребром.

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

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

Для приведённого примера из вершины $6$ в вершину $12$ ведут четыре пути ($6–7–100–12, 6–1–7–100–12, 6–1–100–12, 6–1–4–100–12$), столько же — из $6$ в $100$; из $1$ в $100$ и из $1$ в $12$ — по три пути; для остальных пар путей меньше. Верным ответом будет $4$.

Для фиксированной конечной вершины $t$ одна функция с запоминанием даёт число путей из любой вершины в $t$, поэтому достаточно $50$ функций — по одной на каждую возможную цель — и перебора начальных вершин. Все вершины (включая те, что встречаются только как концы рёбер) должны участвовать в переборе и как начала, и как концы.

from functools import lru_cache
import sys
sys.setrecursionlimit(10000)
g = {}                                   # вершина -> список соседей
for line in open('23_30.txt'):
    s = line.split()
    if len(s) < 3:
        continue
    a, b = int(s[0]), int(s[1])          # веса не нужны
    g.setdefault(a, []).append(b)
verts = set(g)                           # все вершины графа
for v in g:
    verts |= set(g[v])
best = 0
for t in verts:                          # для каждой конечной вершины t
    @lru_cache(None)
    def f(v):                            # число путей v -> t
        if v == t:
            return 1
        return sum(f(u) for u in g.get(v, []))
    for s in verts:
        if s != t:
            best = max(best, f(s))
print(best)

Второй способ — симметричный: фиксируем начальную вершину $s$ и считаем число путей из $s$ в каждую вершину по обратному графу (продолжение после чтения графа и определения verts):

r = {}                                   # обратный граф
for a in g:
    for b in g[a]:
        r.setdefault(b, []).append(a)
best = 0
for s in verts:                          # для каждой начальной вершины s
    @lru_cache(None)
    def h(v):                            # число путей s -> v
        if v == s:
            return 1
        return sum(h(a) for a in r.get(v, []))
    for t in verts:
        if t != s:
            best = max(best, h(t))
print(best)

Максимум достигается для пары $845 → 626$. Для сравнения: из $1$ в $100$ ведут $19 993 000$ путей, наибольшее число путей из вершины $1$ — $286 909 311$, наибольшее число путей в вершину $100$ — $33 502 334$.

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

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