stringtranslate.com

Conectividad dinámica

En informática y teoría de grafos , una estructura de conectividad dinámica es una estructura de datos que mantiene dinámicamente información sobre los componentes conectados de un grafo.

El conjunto V de vértices del grafo es fijo, pero el conjunto E de aristas puede cambiar. Los tres casos, en orden de dificultad, son:

Después de cada adición o eliminación de un borde, la estructura de conectividad dinámica debe adaptarse de manera tal que pueda dar respuestas rápidas a consultas del tipo "¿hay un camino entre x e y ?" (equivalentemente: "¿los vértices x e y pertenecen al mismo componente conectado?").

Conectividad incremental

Si sólo se pueden añadir aristas, entonces el problema de conectividad dinámica se puede resolver mediante una estructura de datos de conjunto disjunto . Cada conjunto representa un componente conectado; existe un camino entre x e y si y sólo si pertenecen al mismo conjunto. El tiempo amortizado por operación es , donde n es el número de vértices y α es la función inversa de Ackermann . [1] [2]

Conectividad decremental

El caso en el que sólo se pueden eliminar los bordes fue resuelto por Shimon Even y Yossi Shiloach. [3]

La estructura utiliza una tabla que especifica, para cada vértice, el nombre del componente al que pertenece. Por lo tanto, una consulta de conectividad lleva un tiempo constante. El desafío es actualizar la tabla cuando se elimina una arista.

Grafos acíclicos (bosques)

Cuando se elimina la arista u - v en un bosque , el árbol que contiene esa arista se divide en dos árboles: uno de ellos contiene u y el otro contiene v . La tabla se actualiza de la siguiente manera.

Como siempre cambiamos el nombre del subcomponente más pequeño, el tiempo amortizado para una operación de eliminación es .

Gráficos generales

Cuando se elimina una arista en un grafo general, no sabemos si su componente permanece como un solo componente (conectado por otras aristas) o se divide en dos componentes. Por lo tanto, utilizamos dos procesos que se ejecutan en paralelo (o de forma intercalada). El proceso A verifica si la eliminación de la arista rompe un componente y, si lo hace, ambos procesos se detienen. El proceso B verifica si la eliminación de la arista no rompe el componente al que pertenece y, si no lo hace, nuevamente ambos procesos se detienen.

Proceso A
es similar al caso del gráfico acíclico: hay dos subprocesos que escanean desde ambos extremos del borde eliminado. Si uno de los subprocesos termina antes de llegar al otro extremo, esto significa que el componente se divide en dos subcomponentes y se actualiza el nombre del subcomponente más pequeño, como antes. Por lo tanto, el tiempo amortizado para una operación de eliminación es nuevamente .
Proceso B
utiliza una estructura de amplitud (BFS) , que se inicializa de la siguiente manera. Se elige un vértice r y la BFS comienza a partir de él. El único vértice en el nivel 0 es r . Todos los vértices de distancia i desde la raíz están en el nivel i . Si G no está conectado, se inicia un nuevo escaneo en algún vértice no escaneado v , v se coloca en el nivel 1 y una arista artificial conecta v con la raíz r ; todos los vértices de distancia i desde v ahora están en el nivel i +1, etc. Las aristas artificiales se introducen para mantener todos los componentes conectados en una estructura BFS y se usan solo para este propósito. Claramente, las aristas artificiales se usan solo en el proceso B.

La estructura tiene las siguientes propiedades. Un vértice v en el nivel i , i > 0, tiene solo tres tipos de aristas: aristas hacia atrás que lo conectan al nivel i −1 (hay al menos una arista de este tipo, que puede ser artificial), aristas locales que lo conectan a otras aristas en el nivel i (hay cero o más aristas de este tipo), o aristas hacia adelante que lo conectan a aristas en el nivel i +1 (hay cero o más aristas de este tipo). Entonces, para cada vértice v , mantenemos tres conjuntos de aristas (hacia atrás, local y hacia adelante).

Cuando se elimina una arista u - v , hay dos opciones: o u y v están en el mismo nivel, o están en niveles cuyo número difiere en 1.

Caso 1
Tanto u como v están en el mismo nivel. En este caso, la eliminación de la arista no puede cambiar los componentes. La arista simplemente se elimina de los conjuntos de aristas locales de u y v , y el proceso B se detiene (y, por lo tanto, el proceso A también se detiene). Nuestra estructura BFS sigue siendo válida.
Caso 2
u y v están en niveles diferentes. Sin pérdida de generalidad, supongamos que u está en el nivel i −1 y v está en el nivel i ; por lo tanto, se debe eliminar la arista de adelante( u ) y de atrás( v ).
Caso 2.1
Si el nuevo reverse( v ) no está vacío, entonces los componentes no han cambiado: hay otros bordes que conectan v hacia atrás. El proceso B se detiene (y el proceso A también se detiene).
Caso 2.2
Si el nuevo reverse( v ) está vacío, entonces v ya no está conectado al nivel i −1, y por lo tanto su distancia desde la raíz ya no es i ; debe ser al menos i +1. Además, puede haber otros vértices, conectados a v , cuya distancia desde la raíz aumenta como resultado de la eliminación. Para calcular las distancias actualizadas, utilizamos una cola Q, que inicialmente contiene solo el vértice v .

Mientras Q no esté vacío:

  1. w  := sacar de la cola(Q)
  2. Elimina w de su nivel (digamos, j ) y colócalo en el siguiente nivel ( j +1).
  3. Actualización a los vecinos locales:
    • Para cada borde wx en local( w ), quítelo de local( x ) y colóquelo en forward( x ).
    • hacia atrás( w ) := local( w )
  4. Actualización para futuros vecinos:
    • Para cada borde w - x en forward( w ), quítelo de toward( x ) y póngalo en local( x ); si el nuevo toward( x ) está vacío, ponga x en cola en Q.
    • local( w ) := adelante( w )
    • forward( w ) := conjunto vacío
  5. Si el nuevo reverse( w ) está vacío, vuelva a poner en cola w en Q.

Si la eliminación de la arista no rompe ningún componente y estamos en el caso 2.2, entonces eventualmente el procedimiento se detendrá. En este caso es fácil ver que la estructura BFS se mantiene correctamente. Si su eliminación rompe un componente, entonces el procedimiento no se detendrá por sí mismo. Sin embargo, el proceso A, reconociendo la ruptura, se detendrá, y ambos procesos se detendrán. En este caso todos los cambios hechos en la estructura BFS son ignorados, y volvemos a la estructura BFS que teníamos justo antes de la eliminación, excepto que la arista eliminada ahora es reemplazada por una arista artificial. Claramente, en este caso v es ahora la raíz de un árbol que incluye el nuevo componente, y quizás componentes adicionales, a través de algunas otras aristas artificiales. Además, no hay aristas que conecten los descendientes de v con ningún vértice que no sea descendiente de v , excepto la arista artificial ⁠ ⁠ . [4]

Siempre que se procesa una arista en el procedimiento, uno de sus puntos finales desciende un nivel. Dado que el nivel más bajo que puede alcanzar un vértice en ejecuciones que terminan con el proceso B es , el costo por arista está limitado por . Por lo tanto, el tiempo amortizado por operación de eliminación es .

Conectividad totalmente dinámica

Grafos acíclicos (bosques)

Un bosque se puede representar mediante una colección de árboles de corte de enlaces o árboles de Euler Tour . Entonces, el problema de conectividad dinámica se puede resolver fácilmente, ya que para cada dos nodos x,y, x está conectado a y si y solo si FindRoot(x)=FindRoot(y). El tiempo de actualización amortizado y el tiempo de consulta son ambos O(log( n )).

Gráficos generales

Un gráfico general se puede representar mediante su bosque de expansión , un bosque que contiene un árbol para cada componente conectado del gráfico. A este bosque de expansión lo llamamos F . F a su vez se puede representar mediante un bosque de árboles de Euler .

Las operaciones de consulta e inserción se implementan utilizando las operaciones correspondientes en los árboles ET que representan a F. La operación más complicada es la de eliminar y, en particular, la de eliminar una arista que se encuentra en uno de los árboles de expansión de F. Esto divide el árbol de expansión en dos árboles, pero es posible que exista otra arista que los conecte. El desafío es encontrar rápidamente una arista de reemplazo, si existe. Esto requiere una estructura de datos más compleja. A continuación se describen varias de estas estructuras.

La estructura de niveles

A cada arista del gráfico se le asigna un nivel . Sea L = lg n . El nivel de cada arista insertada en el gráfico se inicializa en L y puede disminuir hacia 0 durante las operaciones de eliminación.

Para cada i entre 0 y L , definamos Gi como el subgrafo que consiste en aristas que están en el nivel i o menor, y Fi como un bosque de expansión de Gi . Nuestro bosque F de antes ahora se llama FL . Mantendremos una secuencia decreciente de bosques FL ⊇ ... ⊇ F 0. [5] [6]

Operaciones

Las operaciones de consulta e inserción utilizan únicamente el bosque más grande FL . Los subgrafos más pequeños se consultan únicamente durante una operación de eliminación y, en particular, al eliminar una arista que se encuentra en uno de los árboles de expansión de FL .

Cuando se elimina una arista e = xy , primero se la elimina de FL y de todos los bosques de expansión más pequeños a los que pertenece, es decir, de cada Fi con i ≥ nivel( e ). Luego buscamos una arista de reemplazo.

Comience con el bosque de expansión más pequeño que contenía e , es decir, Fi con i = nivel ( e ). La arista e pertenece a un cierto árbol TFi . Después de la eliminación de e , el árbol T se divide en dos árboles más pequeños: Tx que contiene el nodo x y Ty que contiene el nodo y . Una arista de Gi es una arista de reemplazo, si y solo si conecta un nodo en Tx con un nodo en Ty . Supongamos que Tx es el árbol más pequeño (es decir, contiene como máximo la mitad de los nodos de T ; podemos saber el tamaño de cada subárbol mediante una anotación agregada a los árboles de Euler).

Primero disminuimos el nivel de cada borde de Tx en 1. Luego recorremos todos los bordes ε con nivel i y al menos un nodo en Tx :

Análisis

El nivel de cada arista se reducirá como máximo lg n veces. ¿Por qué? Porque con cada reducción, cae en un árbol cuyo tamaño es como máximo la mitad del tamaño de su árbol en el nivel anterior. Por lo tanto, en cada nivel i , el número de nodos en cada componente conectado es como máximo 2 i . Por lo tanto, el nivel de una arista siempre es como mínimo 0.

Cada arista cuyo nivel se reduce, lleva tiempo para encontrarlo (usando las operaciones del árbol ET). En total, cada arista insertada lleva tiempo hasta que se elimina, por lo que el tiempo amortizado para la eliminación es . La parte restante de la eliminación también lleva tiempo, ya que tenemos que eliminar la arista de la mayoría de los niveles, y eliminar de cada nivel lleva (nuevamente usando las operaciones ET).

En total, el tiempo amortizado por actualización es de . El tiempo por consulta se puede mejorar a .

Sin embargo, el tiempo por actualización en el peor de los casos podría ser de . La cuestión de si se puede mejorar el tiempo en el peor de los casos había sido una pregunta abierta, hasta que la estructura Cutset la resolvió afirmativamente.

La estructura Cutset

Dado un grafo G(V,E) y un subconjunto T⊆V, defina cutset(T) como el conjunto de aristas que conectan T con V\T. La estructura cutset es una estructura de datos que, sin mantener todo el grafo en la memoria, puede encontrar rápidamente una arista en el cutset, si dicha arista existe. [7]

Comience por asignar un número a cada vértice. Supongamos que hay n vértices; entonces, cada vértice puede representarse mediante un número con lg( n ) bits. A continuación, asigne un número a cada arista, que es una concatenación de los números de sus vértices: un número con 2 lg( n ) bits.

Para cada vértice v , calcule y mantenga xor( v ), que es el xor de los números de todos los bordes adyacentes a él.

Ahora, para cada subconjunto T⊆V, es posible calcular xor(T) = el xor de los valores de todos los vértices en T. Consideremos una arista e = uv que es una arista interna de T (es decir, tanto u como v están en T). El número de e se incluye dos veces en xor(T): una para u y otra para v . Como el xor de cada número consigo mismo es 0, e se anula y no afecta a xor(T). Por lo tanto, xor(T) es en realidad el xor de todas las aristas en cutset(T). Hay varias opciones:

Nuestro objetivo ahora es abordar esta tercera opción.

Primero, crea una secuencia de lg( n ) niveles de las estructuras cutset, cada uno de los cuales contiene aproximadamente la mitad de las aristas del nivel superior (es decir, para cada nivel, elige cada arista del nivel superior con probabilidad 1/2). Si en el primer nivel xor(T) devuelve un valor ilegal, lo que significa que cutset(T) tiene dos o más aristas, entonces existe la posibilidad de que en el siguiente nivel, que contiene menos aristas, xor(T) devuelva un valor legal ya que cutset(T) contendrá una sola arista. Si xor(T) aún devuelve un valor ilegal, continúa al siguiente nivel, etc. Dado que la cantidad de aristas está disminuyendo, hay dos casos:

Es posible demostrar que la probabilidad de éxito es al menos 1/9.

A continuación, cree una colección de C  lg( n ) versiones independientes de la estructura de niveles, donde C es una constante. En cada versión, realice una reducción aleatoria independiente de los bordes de un nivel a otro. Pruebe cada consulta en cada una de las versiones hasta que una de ellas tenga éxito. La probabilidad de que todas las versiones fallen es, como máximo:

Mediante la selección adecuada de C podemos hacer que la probabilidad de falla sea arbitrariamente cercana a 0.

Operaciones

Podemos agregar una estructura de corte a una estructura de conectividad dinámica.

Las operaciones de inserción y eliminación en la estructura cutset se realizan exactamente de la misma manera: el borde insertado/eliminado se combina con XOR en ambos puntos finales.

Cuando se elimina un borde del bosque de expansión utilizado para la estructura de conectividad dinámica, se utiliza la estructura de corte para encontrar un borde de reemplazo.

Análisis

Una estructura de cutset única requiere solo O ( n lg n ) de memoria: solo un único número, con 2 lg n bits, para cada uno de los n vértices. No tenemos que mantener los bordes mismos. Para gráficos densos, esto es mucho más económico que mantener el gráfico completo en la memoria.

Tenemos que mantener lg( n ) versiones, cada una de las cuales contiene lg( n ) niveles. Por lo tanto, el requerimiento total de memoria es ⁠ ⁠ .

El tiempo de consulta es O (polylog( n )) en el peor de los casos. Esto contrasta con la estructura de nivel, en la que el tiempo de consulta es O (polylog( n )) amortizado, pero el tiempo en el peor de los casos es O ( n ).

Conectividad dinámica offline

Si el orden en el que se eliminarán las aristas se conoce de antemano, podemos resolver el problema de conectividad dinámica a tiempo por consulta. Si podemos mantener un bosque de máxima expansión donde las aristas se ordenan por su tiempo de eliminación, sabemos que cuando eliminamos alguna arista que está en el bosque, no hay ninguna arista posible que pueda reemplazarla. Si hubiera alguna arista que conectara los mismos dos componentes que la arista eliminada, entonces esta otra arista habría sido parte del bosque de máxima expansión en lugar de la arista que eliminamos. Esto hace que la operación de eliminación sea trivial: simplemente necesitamos dividir el árbol en sus dos partes si la arista que se eliminará es parte de nuestro bosque, o ignorar la operación en caso contrario.

Añadir una arista es un poco más complicado. Si añadimos una arista e de u a v, entonces si u y v no están conectadas, esta arista será parte del bosque de máxima expansión. Si están conectadas, queremos añadir u->v a nuestro bosque si puede mejorar nuestro bosque de máxima expansión. Para ello, necesitamos comprobar rápidamente qué arista tiene el menor tiempo de eliminación en la ruta de u a v. Si el tiempo de eliminación de esta arista es posterior al tiempo de eliminación de e, entonces e no puede mejorar nuestro bosque de máxima expansión. De lo contrario, la otra arista debe eliminarse y reemplazarse por e.

Esto requiere que hagamos las siguientes operaciones: agregar un borde, cortar un borde y consultar el borde mínimo en una ruta, lo que se puede hacer con bastante facilidad con un árbol de corte de enlace en log(n) por operación.

Véase también

Referencias

  1. ^ Tarjan, Robert Endre (1975). "Eficiencia de un algoritmo de unión de conjuntos bueno pero no lineal". Revista de la ACM . 22 (2): 215–225. CiteSeerX  10.1.1.399.6704 . doi :10.1145/321879.321884. S2CID  11105749.
  2. ^ Tarjan, Robert Endre (1979). "Una clase de algoritmos que requieren tiempo no lineal para mantener conjuntos disjuntos". Journal of Computer and System Sciences . 18 (2): 110–127. doi : 10.1016/0022-0000(79)90042-4 .
  3. ^ Shiloach, Y.; Even, S. (1981). "Un problema de eliminación de aristas en línea". Revista de la ACM . 28 : 1–4. doi :10.1145/322234.322235. S2CID  207746822.
  4. ^ Una forma de lograr el retorno a la estructura anterior al borrado de e sin tener que copiar toda la estructura es mantener en una pila todos los cambios que se produjeron en la estructura BFS desde el borrado de e y deshacerlos uno por uno. De esta forma el tiempo de procesamiento solo se multiplica por una constante.
  5. ^ Holm, J.; De Lichtenberg, K.; Thorup, M. (2001). "Algoritmos polilogarítmicos deterministas totalmente dinámicos para conectividad, árbol de expansión mínimo, 2 aristas y biconectividad". Revista de la ACM . 48 (4): 723. doi :10.1145/502090.502095. S2CID  7273552.
  6. ^ Problemas de grafos dinámicos - en Apuntes de clase sobre estructuras de datos avanzadas. Prof. Erik Demaine; Escriba: Katherine Lai.
  7. ^ Kapron, BM; King, V.; Mountjoy, B. (2013). Conectividad de grafos dinámicos en el peor caso polilogarítmico . Actas del vigésimo cuarto simposio anual ACM-SIAM sobre algoritmos discretos. p. 1131. doi :10.1137/1.9781611973105.81. ISBN 978-1-61197-251-1.
  8. ^ Existe una pequeña probabilidad de que la operación xor de varias aristas diferentes dé como resultado un número que sea el número de otra arista. Esto podría dar lugar a un falso positivo. Para reducir la probabilidad de este evento, podemos ampliar el dominio de los números de vértices a, digamos, n 3 en lugar de n . Entonces, si hay más de una arista en cutset(T), xor(T) será casi con certeza un valor sin sentido, como se indicó anteriormente.