Постепенно обнаруживать доминаторов в Дагс
Предположим, что у нас есть DAG с одним источником. Я хотел бы найти узлы n
такие, что любой полный путь от источника проходит через n
(т. е. n
доминирует над всеми приемниками). Другими словами: если мы удалим все последователи n
, то все пути закончатся в n
. Проблема заключается в том, что узлы постепенно помечаются как удаленные в DAG. Поскольку узлы помечены как удаленные, другие узлы могут начать удовлетворять вышеуказанному свойству. Как я могу эффективно обнаружить это, когда это происходит?
Бонус указывает , что структура данных может сделать это с несколькими источниками более эффективным способом, чем выполнение алгоритма для одного источника отдельно на каждом из источников.
1 ответ:
Топологически отсортировать эта группа, чтобы установить какой-то порядок для его узлов. Для каждого узла его значение будет равно числу исходящих ребер из всех предыдущих узлов минус число входящих ребер во все предыдущие узлы и текущий узел. Значение для узла "доминатор" всегда равно нулю.
После того, как некоторый узел помечен как "удаленный", поместите его предшественников и преемников в приоритетную очередь. Приоритет определяется топологическим порядком сортировки. Обновите значения для всех узлов, следуя за" удаленным " узлом (добавьте число входящих узлов и вычтите число исходящих узлов для этого узла). В то же время (в том же порядке) уменьшите значение для каждого узла между предшествующим узлом в очереди приоритетов и "удаленным" узлом и увеличьте значение для каждого узла, начиная с узла-преемника в очереди приоритетов. Остановка, когда значение некоторого узла уменьшается до нуля. Это новый узел "доминатор". Если все узлы "доминатора" необходимы, продолжайте до конца графика.
delete(delNode): for each predecessor in delNode.predecessors: queue.add(predecessor) for each successor in delNode.successors: queue.add(successor) for each node in DAG: if queue.top.priority == node.priority > delNode.priority: ++accumulator node.value += accumulator if node.value == 0: dominatorDetected(node) if node.priority == delNode.priority: accumulator += (delNode.predecessors.size - delNode.successors.size) node.value = -1 if queue.top.priority == node.priority: queue.pop() if node.priority < delNode.priority: --accumulator if queue.empty: stop
Для нескольких в исходном случае можно использовать тот же алгоритм, но сохранить список "значений" для каждого узла, по одному значению для каждого источника. Сложность алгоритма
O(Nodes * Sources)
такая же, как и для независимого поиска по каждому из источников. Но программа может быть сделана более эффективной, если используется векторизация. "значения" могут обрабатываться параллельно с инструкциями SIMD. Современные компиляторы могут выполнять автоматическую векторизацию для достижения этой цели.