Найти SCC для графа (алгоритм Тарьяна или двойной запуск DFS).
Для каждого SCC вычислите сумму весов его узлов, обозначьте это значение PARTIAL-SUM.
Итерация по SCC в обратном топологическом порядке; для каждого узла в каждом SCC его SUM будет суммой всех значений SUM смежных SCC плюс его собственное значение PARTIAL-SUM.
Линейное время работы O(E+V)
, поскольку обнаружение SCC является линейным, топологическая сортировка линейной, а суммирование линейным, поскольку мы посещаем каждый SCC не более одного раза и каждую ветвь не более одного раза.
EDIT
Как было отмечено в комментариях, tzkuzzy параллельные пути создают проблему. Это легко решается простым запуском DFS на графике SCC. На любом перекрестке мы просто берем уже посещенный узел вверх по дереву DFS, пока не достигнем не полностью искомого родителя, у этой пары узлов (посещенный снизу и предок) есть два разных пути между ними, мы составьте список для каждого узла таких потомков, а при суммировании просто вычтите их значение PARTIAL-SUM.
Так что если:
u
/ \
\ /
w
Наша DFS выберет перекрестную границу, соединяющую дочерний узел с u
до w
, и проследит до u
(для тех, кто знаком с типичной DFS, изучаемой в школах, самое простое объяснение состоит в том, что u
характеризуется как первый серый предок w
), поэтому мы добавляем w
в список, который мы поддерживаем u
.
Затем, когда мы суммируем соседние SCC каждого SCC, как описано, мы добавляем дополнительный шаг, где мы перебираем упомянутый список и просто вычитаем значения PARTIAL-SUM.
Сам DFS все еще линейный. Откат от узла к предку может быть линейным, если мы кешируем результаты (таким образом, мы не пересекаем одно и то же ребро более одного раза). И дополнительная работа при суммировании составляет самое большее O(V)
, поэтому мы не изменили время выполнения.
EDIT
Включение-исключение делает это более трудным, чем я сначала думал. Это решение не является полным и не работает. Простая BFS для каждого узла дороже, но проще и будет работать.