stringtranslate.com

Динамическое подключение

В вычислительной технике и теории графов динамическая структура связности — это структура данных, которая динамически поддерживает информацию о связанных компонентах графа.

Множество вершин V графа фиксировано, но множество ребер E может меняться. Три случая, в порядке сложности, следующие:

После каждого добавления/удаления ребра динамическая структура связности должна адаптироваться таким образом, чтобы она могла быстро давать ответы на запросы вида «существует ли путь между x и y ?» (эквивалентно: «принадлежат ли вершины x и y одному и тому же связному компоненту?»).

Инкрементное подключение

Если ребра можно только добавлять, то проблема динамической связности может быть решена с помощью структуры данных непересекающихся множеств . Каждое множество представляет собой связанный компонент; между x и y существует путь тогда и только тогда, когда они принадлежат одному и тому же множеству. Амортизированное время на операцию равно , где n — число вершин, а α — обратная функция Аккермана . [1] [2]

Декрементная связность

Случай, когда ребра можно только удалять, был решен Шимоном Эвеном и Йосси Шилоахом. [3]

Структура использует таблицу , которая определяет для каждой вершины имя компонента, к которому она принадлежит. Таким образом, запрос на связность занимает постоянное время. Задача состоит в обновлении таблицы при удалении ребра.

Ациклические графы (леса)

Когда ребро u - v удаляется в лесу , дерево, содержащее это ребро, разбивается на два дерева: одно из них содержит u , а другое содержит v . Таблица обновляется следующим образом.

Поскольку мы всегда переименовываем меньший подкомпонент, амортизированное время для операции удаления составляет .

Общие графики

Когда ребро удаляется в общем графе, мы не знаем, остается ли его компонент единым компонентом (соединенным другими ребрами) или разбивается на два компонента. Поэтому мы используем два процесса, которые выполняются параллельно (или чередующимся образом). Процесс A проверяет, нарушает ли удаление ребра компонент, и если это так, оба процесса останавливаются. Процесс B проверяет, не нарушает ли удаление ребра компонент, к которому оно принадлежит, и если это не так, снова оба процесса останавливаются.

Процесс А
похож на случай ациклического графа: есть два подпроцесса, которые сканируют с обоих концов удаленного ребра. Если один из подпроцессов завершается до достижения другого конца, это означает, что компонент разбивается на два подкомпонента, и имя меньшего подкомпонента обновляется, как и раньше. Таким образом, амортизированное время для операции удаления снова равно .
Процесс Б
использует структуру поиска в ширину (BFS) , которая инициализируется следующим образом. Выбирается вершина r , и BFS начинается с нее. Единственная вершина на уровне 0 — r . Все вершины на расстоянии i от корня находятся на уровне i . Если G не подключен, новое сканирование начинается с некоторой несканированной вершины v , v помещается на уровень 1, а искусственное ребро соединяет v с корнем r ; все вершины на расстоянии i от v теперь находятся на уровне i +1 и т. д. Искусственные ребра вводятся для того, чтобы сохранить все связанные компоненты в одной структуре BFS, и используются только для этой цели. Очевидно, что искусственные ребра используются только в процессе B.

Структура имеет следующие свойства. Вершина v на уровне i , i > 0, имеет только три типа ребер: обратные ребра , которые соединяют ее с уровнем i −1 (существует по крайней мере одно такое ребро, которое может быть искусственным), локальные ребра , которые соединяют ее с другими ребрами на уровне i (существует ноль или более таких ребер), или прямые ребра , которые соединяют ее с ребрами на уровне i +1 (существует ноль или более таких ребер). Таким образом, для каждой вершины v мы поддерживаем три набора ребер (обратные, локальные и прямые).

При удалении ребра u - v возможны два варианта: либо u и v находятся на одном уровне, либо они находятся на уровнях, номера которых отличаются на 1.

Случай 1
и u, и v находятся на одном уровне. В этом случае удаление ребра не может изменить компоненты. Ребро просто удаляется из наборов локальных ребер u и v , и процесс B останавливается (и, следовательно, процесс A тоже останавливается). Наша структура BFS по-прежнему действительна.
Случай 2
u и v находятся на разных уровнях. Без потери общности предположим, что u находится на уровне i −1, а v — на уровне i ; следовательно, ребро должно быть удалено из forward( u ) и backward( v ).
Случай 2.1
Если новый backward( v ) не пуст, то компоненты не изменились: есть другие ребра, которые соединяют v в обратном направлении. Процесс B останавливается (и процесс A тоже останавливается).
Случай 2.2
Если новый backward( v ) пуст, то v больше не связан с уровнем i −1, и поэтому его расстояние от корня больше не i ; оно должно быть не менее i +1. Кроме того, могут быть другие вершины, связанные с v , расстояние от корня которых увеличивается в результате удаления. Для вычисления обновленных расстояний мы используем очередь Q, которая изначально содержит только вершину v .

Пока Q не пуст:

  1. w  := dequeue(Q)
  2. Удалите w с его уровня (скажем, j ) и поместите его на следующий уровень ( j +1).
  3. Обновление местных соседей:
    • Для каждого ребра wx в local( w ) удалите его из local( x ) и поместите в forward( x ).
    • назад( w ) := локально( w )
  4. Обновление прямых соседей:
    • Для каждого ребра w - x в forward( w ) удалите его из backward( x ) и поместите его в local( x ); если новый backward( x ) пуст, поставьте x в очередь на Q.
    • локальный( w ) := вперед( w )
    • вперед( w ) := пустой набор
  5. Если новый backward( w ) пуст, снова поставьте w в очередь Q.

Если удаление ребра не нарушает ни одного компонента, и мы находимся в случае 2.2, то в конечном итоге процедура остановится. В этом случае легко увидеть, что структура BFS поддерживается правильно. Если его удаление нарушает компонент, то процедура не остановится сама по себе. Однако процесс A, распознающий разрыв, остановится, и оба процесса остановятся. В этом случае все изменения, внесенные в структуру BFS, игнорируются, и мы возвращаемся к структуре BFS, которая была у нас непосредственно перед удалением, за исключением того, что удаленное ребро теперь заменено искусственным ребром. Очевидно, что в этом случае v теперь является корнем дерева, которое включает новый компонент и, возможно, дополнительные компоненты, через некоторые другие искусственные ребра. Кроме того, нет ребер, соединяющих потомков v с какими-либо вершинами, которые не являются потомками v , за исключением искусственного ребра ⁠ ⁠ . [4]

всякий раз, когда ребро обрабатывается в процедуре, одна из его конечных точек опускается на один уровень. Поскольку самый низкий уровень, которого вершина может достичь в запусках, завершаемых процессом B, равен , стоимость одного ребра ограничена . Следовательно, амортизированное время на операцию удаления равно .

Полностью динамическое подключение

Ациклические графы (леса)

Лес может быть представлен с помощью набора деревьев ссылок или деревьев Эйлера . Тогда проблема динамической связности может быть легко решена, так как для каждых двух узлов x,y, x соединен с y тогда и только тогда, когда . Амортизированное время обновления и время запроса составляют O(log( n )).

Общие графики

Общий граф может быть представлен его остовным лесом - лесом , который содержит дерево для каждого связного компонента графа. Мы называем этот остовной лес F. Сам F может быть представлен лесом деревьев эйлерова тура .

Операции Query и Insert реализуются с использованием соответствующих операций на деревьях ET, представляющих F. Сложной операцией является Delete, и в частности удаление ребра, которое содержится в одном из остовных деревьев F. Это разбивает остовное дерево на два дерева, но возможно, что есть еще одно ребро, которое их соединяет. Задача состоит в том, чтобы быстро найти такое заменяющее ребро, если оно существует. Для этого требуется более сложная структура данных. Несколько таких структур описаны ниже.

Структура уровня

Каждому ребру в графе назначается уровень . Пусть L =lg n . Уровень каждого ребра, вставленного в граф, инициализируется значением L и может уменьшаться до 0 во время операций удаления.

Для каждого i между 0 и L определим Gi как подграф, состоящий из ребер, которые находятся на уровне i или ниже, а Fi — остовной лес Gi . Наш лес F из предыдущего теперь называется FL . Мы сохраним убывающую последовательность лесов FL ⊇ ... ⊇ F 0. [5] [6]

Операции

Операции Query и Insert используют только самый большой лес FL . Меньшие подграфы просматриваются только во время операции Delete, и в частности, удаления ребра, которое содержится в одном из остовных деревьев FL .

Когда удаляется такое ребро e = xy , оно сначала удаляется из FL и из всех меньших остовных лесов, к которым оно принадлежит, т.е. из каждого Fi с i ≥ level( e ). Затем мы ищем заменяющее ребро.

Начнем с наименьшего остовного леса, содержащего e , а именно, Fi с i = level( e ). Ребро e принадлежит определенному дереву TFi . После удаления e дерево T разбивается на два меньших дерева: Tx , содержащее узел x , и Ty , содержащее узел y . Ребро Gi является ребром замены, если и только если оно соединяет узел в Tx с узлом в Ty . Предположим wlog , что Tx является меньшим деревом (т. е. содержит не более половины узлов T ; мы можем определить размер каждого поддерева с помощью аннотации, добавленной к деревьям Эйлера).

Сначала мы уменьшаем уровень каждого ребра Tx на 1. Затем мы перебираем все ребра ε с уровнем i и хотя бы одним узлом в Tx :

Анализ

Уровень каждого ребра будет уменьшен не более чем в lg n раз. Почему? Потому что с каждым уменьшением оно попадает в дерево, размер которого не более чем в два раза меньше размера его дерева на предыдущем уровне. Таким образом, на каждом уровне i количество узлов в каждом связанном компоненте не более 2 i . Следовательно, уровень ребра всегда не менее 0.

Каждое ребро, уровень которого понижен, требует времени для поиска (с использованием операций дерева ET). В общей сложности, каждое вставленное ребро требует времени, пока оно не будет удалено, поэтому амортизированное время удаления составляет . Оставшаяся часть удаления также требует времени, поскольку нам нужно удалить ребро из большинства уровней, а удаление из каждого уровня занимает (снова с использованием операций ET).

В целом амортизированное время на обновление составляет . Время на запрос можно улучшить до .

Однако худшее время на обновление может быть . Вопрос о том, можно ли улучшить худшее время, оставался открытым, пока он не был решен утвердительно структурой Cutset.

Структура Cutset

Для данного графа G(V,E) и подмножества T⊆V определим cutset(T) как множество ребер, соединяющих T с V\T. Структура cutset — это структура данных, которая, не сохраняя весь граф в памяти, может быстро найти ребро в cutset, если такое ребро существует. [7]

Начните с присвоения номера каждой вершине. Предположим, что есть n вершин; тогда каждая вершина может быть представлена ​​числом с lg( n ) битами. Затем присвойте номер каждому ребру, которое является конкатенацией номеров его вершин - число с 2 lg( n ) битами.

Для каждой вершины v вычислите и сохраните xor( v ), который является xor чисел всех смежных с ней ребер.

Теперь для каждого подмножества T⊆V можно вычислить xor(T) = xor значений всех вершин в T. Рассмотрим ребро e = uv , которое является внутренним ребром T (т.е. и u, и v находятся в T). Число e дважды включено в xor(T) - один раз для u и один раз для v . Поскольку xor каждого числа с самим собой равен 0, e обращается в нуль и не влияет на xor(T). Таким образом, xor(T) на самом деле является xor всех ребер в cutset(T). Есть несколько вариантов:

Теперь наша цель — разобраться с этим третьим вариантом.

Сначала создайте последовательность из lg( n ) уровней структур cutset, каждый из которых содержит около половины ребер с верхнего уровня (т. е. для каждого уровня выберите каждое ребро с верхнего уровня с вероятностью 1/2). Если на первом уровне xor(T) возвращает недопустимое значение, что означает, что cutset(T) имеет два или более ребер, то есть вероятность, что на следующем уровне, который содержит меньше ребер, xor(T) вернет допустимое значение, поскольку cutset(T) будет содержать одно ребро. Если xor(T) все еще возвращает недопустимое значение, перейдите на следующий уровень и т. д. Поскольку количество ребер уменьшается, возможны два случая:

Можно доказать, что вероятность успеха составляет не менее 1/9.

Далее создайте коллекцию из C  lg( n ) независимых версий структуры уровня, где C — константа. В каждой версии выполните независимое случайное сокращение ребер от уровня к уровню. Попробуйте каждый запрос на каждой из версий, пока одна из них не увенчается успехом. Вероятность того, что все версии потерпят неудачу, не превышает:

Правильным выбором C мы можем сделать вероятность отказа произвольно близкой к 0.

Операции

Мы можем добавить структуру разрезов к динамической структуре связности.

Операции вставки и удаления в структуре набора разрезов выполняются абсолютно одинаково: вставленное/удалённое ребро подвергается операции XOR с обеими его конечными точками.

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

Анализ

Для одной структуры cutset требуется только O ( n lg n ) памяти — только одно число с 2 lg n битами для каждой из n вершин. Нам не нужно хранить сами ребра. Для плотных графов это намного дешевле, чем хранить весь граф в памяти.

Нам нужно сохранить lg( n ) версий, каждая из которых содержит lg( n ) уровней. Следовательно, общее требование к памяти составляет ⁠ ⁠ .

Время запроса в худшем случае составляет O (polylog( n )). Это контрастирует со структурой Level, в которой время запроса составляет O (polylog( n )) амортизировано, но время в худшем случае составляет O ( n ).

Динамическое подключение в автономном режиме

Если порядок, в котором будут удалены ребра, известен заранее, то мы можем решить проблему динамической связности за время на запрос. Если мы можем поддерживать максимальный охватывающий лес, где ребра упорядочены по времени их удаления, мы знаем, что когда мы удаляем некоторое ребро, которое находится в лесу, нет возможного ребра, которое может его заменить. Если бы было какое-то ребро, которое соединяет те же два компонента, что и удаленное ребро, то это другое ребро было бы частью максимального охватывающего леса вместо ребра, которое мы удалили. Это делает операцию удаления тривиальной: нам просто нужно разделить дерево на две части, если удаляемое ребро является частью нашего леса, или игнорировать операцию в противном случае.

Добавление ребра немного сложнее. Если мы добавим ребро ребро e от u до v, то если u и v не соединены, то это ребро будет частью максимального остовного леса. Если они соединены, мы хотим добавить u->v к нашему лесу, если это может улучшить наш максимальный остовный лес. Для этого нам нужно быстро проверить, какое ребро имеет наименьшее время удаления на пути от u до v. Если время удаления этого ребра наступает после времени удаления e, то e не может улучшить наш максимальный остовный лес. В противном случае другое ребро должно быть удалено и заменено на e.

Для этого нам необходимо выполнить следующие операции: добавить ребро, разрезать ребро и запросить минимальное ребро на пути, что можно довольно легко сделать с помощью дерева разрезов ссылок за log(n) на операцию.

Смотрите также

Ссылки

  1. ^ Тарьян, Роберт Эндре (1975). «Эффективность хорошего, но не линейного алгоритма объединения множеств». Журнал ACM . 22 (2): 215–225. CiteSeerX  10.1.1.399.6704 . doi :10.1145/321879.321884. S2CID  11105749.
  2. ^ Тарьян, Роберт Эндре (1979). «Класс алгоритмов, требующих нелинейного времени для поддержания непересекающихся множеств». Журнал компьютерных и системных наук . 18 (2): 110–127. doi : 10.1016/0022-0000(79)90042-4 .
  3. ^ Шилоах, Y.; Эвен, S. (1981). «Проблема удаления рёбер в режиме онлайн». Журнал ACM . 28 : 1–4. doi : 10.1145/322234.322235. S2CID  207746822.
  4. ^ Один из способов реализовать возврат к структуре, предшествующей удалению e, без необходимости копирования всей структуры — сохранить в стеке все изменения, которые произошли в структуре BFS с момента удаления e, и отменять их одно за другим. Таким образом, время обработки умножается только на константу.
  5. ^ Холм, Дж.; Де Лихтенберг, К.; Торуп, М. (2001). «Полилогарифмические детерминированные полностью динамические алгоритмы для связности, минимального остовного дерева, 2-ребра и бисвязности». Журнал ACM . 48 (4): 723. doi :10.1145/502090.502095. S2CID  7273552.
  6. ^ Задачи динамических графов — в конспекте лекций по продвинутым структурам данных. Проф. Эрик Демейн; Писатель: Кэтрин Лай.
  7. ^ Капрон, Б. М.; Кинг, В.; Маунтджой, Б. (2013). Динамическая связность графа в полилогарифмическом худшем случае времени . Труды двадцать четвертого ежегодного симпозиума ACM-SIAM по дискретным алгоритмам. стр. 1131. doi : 10.1137/1.9781611973105.81. ISBN 978-1-61197-251-1.
  8. ^ Существует небольшая вероятность того, что xor нескольких различных ребер даст число, которое окажется числом другого ребра. Это может привести к ложному срабатыванию. Чтобы уменьшить вероятность этого события, мы можем расширить область чисел вершин, скажем, до n 3 вместо n . Тогда, если в cutset(T) больше одного ребра, xor(T) почти наверняка будет бессмысленным значением, как указано выше.