Топологическая сортировка, чтобы найти количество путей к t

Мне нужно разработать алгоритм O (| V | + | E |), связанный с топологической сортировкой, который в ориентированном ациклическом графе (DAG) определяет количество путей от каждой вершины графа к t (t - узел с степень 0). Я разработал следующую модификацию DFS:

DFS(G,t):
    for each vertex u ∈ V do
        color(u) = WHITE
        paths_to_t(u) = 0
    for each vertex u ∈ V do
        if color(u) == WHITE then
            DFS-Visit(u,t)

DFS-Visit(u,t):
    color(u) = GREY
    for each v ∈ neighbors(u) do
        if v == t then
            paths_to_t(u) = paths_to_t(u) + 1
        else then
            if color(v) == WHITE then
                DFS-Visit(v)
            paths_to_t(u) = paths_to_t(u) + paths_to_t(v)
    color(u) = BLACK

Но я не уверен, связан ли этот алгоритм с топологической сортировкой или мне следует перестроить свою работу с другой точки зрения.


person Stratford    schedule 06.08.2013    source источник
comment
Я предполагаю, что ваш график - это DAG (иначе нет смысла говорить о топологической сортировке или о количестве путей, их может быть бесконечное количество)   -  person amit    schedule 06.08.2013
comment
@amit Да, я поставил вопрос направленный ациклический граф. Я отредактировал, чтобы добавить аббревиатуру DAG   -  person Stratford    schedule 06.08.2013
comment
Ваш алгоритм правильный, вы найдете множество способов t. И вы делаете это топологически правильно: как только вершина u окрашивается в черный цвет, значение path_to_t (u) является правильным - оно соответствует перемещению вершины в стек в алгоритме топологической сортировки.   -  person Sergey Weiss    schedule 06.08.2013


Ответы (1)


Это можно сделать с помощью динамического программирования и топологической сортировки следующим образом:

Topological sort the vertices, let the ordered vertices be v1,v2,...,vn
create new array of size t, let it be arr
init: arr[t] = 1
for i from t-1 to 1 (descending, inclusive):
    arr[i] = 0  
    for each edge (v_i,v_j) such that i < j <= t:
         arr[i] += arr[j]

Когда вы закончите, для каждого i в [1,t] arr[i] указывает количество путей от vi до vt.

Теперь доказать приведенное выше утверждение легко (по сравнению с вашим алгоритмом, который я понятия не имею, верен ли он и как его доказать), это делается по индукции:

База: arr[t] == 1, и действительно, существует единственный путь от t до t, пустой.
Гипотеза: утверждение верно для каждого k в диапазоне m < k <= t
Доказательство: нам нужно доказать, что утверждение верно для m.
Давайте посмотрим на каждый край из vm: (v_m,v_i).
Таким образом, количество путей к vt, начиная с v_m, которые используют это ребро (v_m,v_i). равно arr[i] (предположение индукции). Суммирование всех возможных ребер от v_m дает нам общее количество путей от v_m до v_t - и это именно то, что делает алгоритм.
Таким образом, arr[m] = #paths from v_m to v_t

QED

Сложность по времени:
Первый шаг (топологическая сортировка) занимает O(V+E).
Цикл выполняет итерацию по всем ребрам один раз и по всем вершинам, так что это тоже O(V+E).
Это дает нам общую сложность O(V+E)

person amit    schedule 06.08.2013
comment
Я вообще не знаю, как работает динамическое программирование. :( Забыл указать, что алгоритм должен быть в O (| V | + | E |) - person Stratford; 06.08.2013
comment
@Stratford Я добавил в алгоритм доказательство правильности и небольшую оптимизацию, которая гарантирует, что временная сложность равна O(V+E). Динамическое программирование - это метод, с помощью которого мы строим решения от простого небольшого случая до полного решения проблемы, и это то, что делает цикл после топологической сортировки в псевдокоде. - person amit; 06.08.2013
comment
DP здесь избыточен. Зачем заморачиваться и лишний раз перечислять края, если он уже проделал работу в DFS? - person Sergey Weiss; 06.08.2013
comment
@SergeyWeiss Это предлагаемая альтернатива DFS, я считаю, что это решение очень легко доказать, как его сложность, так и его правильность, и, поскольку вопрос кажется теоретическим, это важный аспект. - person amit; 06.08.2013
comment
@amit Да, подход DP правильный, это просто излишество. И у меня небольшое замечание: дополнительных проверок ребер из вершины v_i не требуется. Поскольку вершины топологически отсортированы, v_j уже обрабатывается на предыдущих итерациях. Следовательно: для каждого ребра (v_i, v_j) arr [i] + = arr [j] - person Sergey Weiss; 06.08.2013
comment
@SergeyWeiss Спасибо вам обоим за вашу помощь! Я сохраню свое решение, если оно верное! :) Но я постараюсь понять, как работает решение, основанное на DP, просто чтобы немного узнать о DP! :) - person Stratford; 06.08.2013
comment
@Stratford Добро пожаловать! DP - очень мощный инструмент, безусловно, стоит освоить эту технику. Есть много сайтов, где можно попрактиковаться в решении задач DP: topcoder, codeforces, SPOJ и т. Д. - person Sergey Weiss; 06.08.2013