Сумма продуктов пути в DAG

Предположим, у нас есть DAG с ребрами, помеченными числами. Определите значение пути как произведение меток. Для каждой пары (источник, приемник) я хочу найти сумму значений всех путей от источника к приемнику. Вы можете сделать это за полиномиальное время с помощью динамического программирования, но есть еще некоторые варианты, которые можно сделать при декомпозиции задачи. В моем случае у меня есть один DAG, который нужно многократно оценивать с разными метками. Мой вопрос: для данного DAG, как мы можем предварительно вычислить хорошую стратегию для многократного вычисления этих значений для разных меток? Было бы неплохо, если бы существовал алгоритм, который находит оптимальный путь, например способ, минимизирующий количество умножений. Но, возможно, это слишком много, я был бы очень доволен алгоритмом, который просто дает хорошую декомпозицию.


person Jules    schedule 12.04.2012    source источник
comment
Вам нужна фактическая сумма по всем путям или просто сравнить эти суммы?   -  person Irit Katriel    schedule 12.04.2012
comment
Вам нужна сумма для каждой отдельной пары (источник, приемник)? Или вы хотите запросить сумму для определенных пар?   -  person zarkon    schedule 25.04.2012
comment
Мне нужна каждая пара (источник, приемник), где источник — это тот, у которого нет предшественников, а приемник — тот, у которого нет преемников (или с заданным набором источников и заданным набором приемников, как вам удобно алгоритм, потому что эти наборы в любом случае легко вычислить).   -  person Jules    schedule 25.04.2012


Ответы (1)


Пусть S — множество источников, V — множество вершин DAG, E — множество ребер, n = |V|, m = |S|, W — матрица размера n x n, в которой хранятся веса ребер, а C — множество ребер. матрица размера m x n такая, что C[i,j] содержит в конце алгоритма сумму значений всех путей от i до j. Для упрощения объяснения и доказательства корректности алгоритма я предполагаю, что вершины графа от 1 до n топологически упорядочены, в котором узлы от 1 до m являются источниками. Это добавляет O(|E|+|V|) к времени работы нашего алгоритма:

Вот псевдокод алгоритма:

1: set C[i,j] to 1 if i=j and i is a source node, and to 0 otherwise.
2: sort the DAG topologically
3: for k=1 to n (vertex traversal in the topological order)
4:   foreach predecessor k' of vertex k
5:     foreach i in S
6:       C[i,k] += C[i,k']*W[k',k]

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

Доказательство правильности: мы доказываем по индукции, что после завершения k-й итерации самого внешнего цикла C[i,k] является суммой значений всех путей от i до k для каждого i в S.
Базовый случай: очевидно для k = 1 (поскольку у первого элемента нет предшественников)
Индукция: предположим C[i, j] вычисляется правильно для всех j ‹ k. Все пути из любого источника i в k должны проходить через предшественника k' источника k. Поскольку мы итерируем в топологическом порядке, k' должно быть меньше k, а согласно нашему предположению индукции C[i,k'] есть сумма значений пути от i до k'. При этом сумма значений путей из i в k, проходящих через конкретного предшественника k', равна сумме значений путей из i в k', т. е. C[i,k'], умноженной на W[k ', к]. Следовательно, сумма значений всех путей от i до k равна сумме C[i,k']*W[k',k] по всем предшественникам k' пути k.

Та же структура графа, другая матрица W: Если нам нужно вычислить матрицу C для разных графов, которые имеют одинаковую структуру, но разные W, мы можем сделать следующее: Пусть C' будет матрицей, элементы которой представляют собой список из 3-кортежей. Замените строку 6 выше на

C'[i,k].append((i,k',k))

А затем, перебирая вершины в топологическом порядке и перебирая кортежи в C'[i,k], вы можете вычислить C[i,k], не глядя на структуру графа. Это потому, что кортежи неявно представляют структуру графа. С точки зрения сложности, это не лучше и не хуже.

person Salem Derisavi    schedule 04.05.2012
comment
Спасибо за Ваш ответ. Алгоритм, который у вас здесь, действительно является одной из таких стратегий. Я рассматривал эту стратегию. Проблема в том, что для некоторых графов он сделает в m раз больше работы, чем необходимо. Например, предположим, что граф имеет m исходных узлов, которые сходятся к одному внутреннему узлу, а затем длинную цепочку узлов к одному приемнику. Этот алгоритм будет работать за O(m*l), где l — длина строки. Если вы вместо этого переходите от стоков к источникам, вы можете сделать это за O (m + 1) работы. Но, делая это, вы имеете другие случаи, которые хуже. Мой вопрос - способ вычислить хорошую стратегию для любого графа. - person Jules; 05.05.2012
comment
Ты прав. Приведенный выше алгоритм не обязательно дает вам оптимальную стратегию. Сложность алгоритма генерации оптимальной стратегии, вероятно, намного выше (просто предположение). Однако есть способы улучшить приведенный выше алгоритм для обработки таких случаев, как вы упомянули, путем предварительной обработки графа: если вершина v имеет одного преемника и k > = 1 предшественников, удалите v и его смежные ребра и замените его k ребрами из каждого из его предшественников своего преемника. Сделайте то же самое, если вершина имеет одного предшественника и k последователей. Каждое из этих правил уменьшает число вершин и ребер на единицу. - person Salem Derisavi; 05.05.2012