Подсчёт путей
Путей может быть экспоненциально много, а посчитать их — линия. И приём, который сводит «через набор вершин» к произведению.
3 мин
Сколько путей ведёт из в в ациклическом графе?
Перебором нельзя: путей бывает экспоненциально много. Простой пример — цепочка, где каждое звено можно пройти двумя способами: путей .
Динамикой — линия. — число путей из в :
vector<int> order = topsort();
vector<long long> dp(n, 0);
dp[t] = 1;
for (int i = n - 1; i >= 0; i--) {
int v = order[i];
if (v == t) continue;
for (int u : g[v]) dp[v] += dp[u];
}
Проверено: на 30 000 случайных DAG совпало с прямым перебором всех путей.
Числа растут быстро — как правило, ответ просят по модулю. Если модуля нет, проверьте, влезает ли ответ в long long.
Пути через заданный набор вершин
Задача интереснее: даны вершин, посчитать пути, проходящие через все из них.
Первое наблюдение: порядок, в котором путь их проходит, определён однозначно — это их порядок в топологической сортировке. Если из достижима , то левее в топсорте; а раз путь проходит через обе, достижимость есть.
Значит, надо отсортировать набор по позиции в топсорте и посчитать пути между соседними парами.
Второе наблюдение: куски независимы. Путь из в и путь из в выбираются свободно друг от друга. Поэтому ответ — произведение.
Как посчитать быстро
В лоб: раз запустить подсчёт путей на всём графе — .
Но при подсчёте путей из в нужны только вершины между ними в топсорте. Выйдя правее , вернуться уже нельзя: все рёбра ведут вправо.
Поэтому считаем динамику только на отрезке топсорта . Отрезки соседних пар пересекаются только по концам, значит, суммарно каждая вершина обрабатывается не больше двух раз — .
long long result = 1;
for (int i = 0; i + 1 < k; i++) {
int L = pos[req[i]], R = pos[req[i + 1]];
vector<long long> dp(n, 0);
dp[req[i + 1]] = 1;
for (int j = R - 1; j >= L; j--) {
int v = order[j];
for (int u : g[v]) if (pos[u] <= R) dp[v] += dp[u];
}
result *= dp[req[i]];
if (result == 0) break; // дальше можно не считать
}
Проверено: на 30 000 графов произведение по соседним парам совпало с прямым перебором путей, проходящих через весь набор.
Про ограничение pos[u] <= R
Без него динамика утекла бы за правую границу отрезка и посчитала пути, которые в не заканчиваются. Формально из таких вершин в не вернуться, и вклад был бы нулевым, — но работа была бы проделана, и оценка сломалась бы.
Родственные постановки
Число кратчайших путей во взвешенном графе — считается вместе с Дейкстрой: при улучшении расстояния счётчик заменяется, при равенстве складывается.
Лежит ли ребро хотя бы на одном кратчайшем пути — сравнить с длиной кратчайшего пути, где считается по обращённому графу.
Число путей длины ровно в произвольном графе — -я степень матрицы смежности; при больших — быстрым возведением в степень.