Encontrar la altura de todos los nodos en un bosque

8

Tengo un bosque, es decir, nodos con bordes dirigidos y sin ciclos (dirigidos o no dirigidos). Defino la altura de un vértice como 0 si no tiene bordes entrantes, o el número máximo de bordes para atravesar en reversa para alcanzar un vértice de altura 0. vingrese la descripción de la imagen aquí

También sé que el grado promedio de un nodo es una constante pequeña, digamos 2 más o menos. Para encontrar la altura de todos los vértices, puedo pensar en dos algoritmos:

Algoritmo Caminante

  1. Pase y marque para vértices sin bordes entrantes.h=0 0
  2. Para cada vértice con , siga los bordes salientes, actualizando la altura de cada vértice encontrado si su altura anterior es menor.h=0 0

Algoritmo de frontera

  1. Pase y marque para vértices sin bordes entrantes, y márquelos como la frontera.h=0 0
  2. Para cada vértice fronterizo, vea si su padre tiene hijos en o debajo de la frontera. Si lo tiene, marque al padre como teniendo más la altura más grande entre sus hijos. Marque al padre como estando en la frontera.1
  3. Repita 2 hasta que no haya nada más allá de la frontera.

Mis preguntas:

  1. ¿Hay un nombre para este problema y una solución más rápida y conocida?
  2. Tiendo a pensar que simplemente caminar desde todos los vértices es la solución más rápida. Estoy en lo cierto?h=0 0
highBandWidth
fuente

Respuestas:

7

En primer lugar, depende un poco cómo puede acceder a sus datos para decir qué algoritmos funcionan mejor.

De todos modos, sugeriría determinar las alturas de arriba hacia abajo en lugar de abajo hacia arriba. Personalmente, creo que un enfoque de arriba hacia abajo es conceptualmente más agradable y más fácil de analizar. Para cualquier vértice en el bosque es cierto quev

altura(v)={(maxtu niño de valtura(tu))+1Si tu no es una hoja0 0de otra manera.

De modo que puede buscar todas las raíces y luego determinar las alturas dividiendo una conquista. Tocará cada vértice como máximo dos veces (escaneando las raíces + atravesando). En el enfoque que ha sugerido, puede que tenga que tocar algunos vértices muchas veces.

Por cierto, dado que tiene un bosque, tiene menos aristas que vértices, por lo que sabe que tiene un grado promedio inferior a dos (y, por lo tanto, puede probar las raíces en tiempo lineal).

A.Schulz
fuente
+1; Las soluciones recursivas son a menudo más fáciles de analizar. También depende de si ya tiene punteros secundarios o no, y si desea una solución basada en bucles o recurrencia.
Joe
¡Me gusta el análisis! ¿Alguien puede ayudar a los novatos señalando cómo convertir esto a la forma iterativa también?
highBandWidth
4

No sé si este problema tiene un nombre oficial o no. Tu título lo resume bastante bien. Subir desde los nodos de altura 0 será rápido, siempre que tenga cuidado de evitar el trabajo duplicado. Suponga que tiene un nodo con muchos hijos y una ruta larga sobre este nodo a la raíz. Supongamos también que las alturas de cada uno de los niños son diferentes. Cada niño puede actualizar la altura del nodo en cuestión. Está bien. Pero también debe evitar actualizar la ruta larga por encima de ese nodo hasta que todos sus hijos hayan informado sus alturas.

El algoritmo resultante se ejecutará en tiempo lineal, y el pseudocódigo se vería así:

initialize a queue Q
initialize all nodes to have a property: maxChildHeight = 0
initialize all nodes of in-degree 0 to have height = 0
Add all nodes of in-degree 0 to Q
while Q is non-empty:
  pop a node v from the front of Q
  subtract 1 from the indegree of the parent of v
  set parent.maxChildHeight = max(height(v), parent.maxChildHeight)
  if the indegree of the parent is 0:
      parent.height =  maxChildHeight + 1
      add the parent to Q
Joe
fuente
3

Un problema tan similar que podría ser de interés es "Prefijo paralelo en árboles direccionados enraizados". El algoritmo encuentra el número de aristas a la raíz de cada nodo. Entonces las raíces terminan con un valor 0, mientras que, por ejemplo, el nodo inferior derecho terminaría con un valor de dos.

Tenga en cuenta que el siguiente algoritmo resuelve el problema más general para los bordes ponderados, pero puede inicializar W (i) en 1 para todo i. Y el sucesor de cada nodo i viene dado por P (i) = j.

for 1 ≤ i ≤ n do in parallel
    S(i) = P(i)
    while S(i) != S(S(i)) do
        W(i) = W(i) + W(S(i))
        S(i) = S(S(i))

La imagen a continuación ilustra la "reducción a la mitad" de las longitudes de ruta y hace que el tiempo de ejecución logarítmico sea fácil de entender. Sin embargo, no muestra las alturas de nodo calculadas.

ingrese la descripción de la imagen aquí

(de "Introducción a los algoritmos paralelos" de Joseph Jaja).

Usando múltiples procesadores, es solucionable en tiempo O (lg n), pero usa operaciones O (n lg n). Hay un truco para llevarlo al trabajo lineal, pero está ligeramente involucrado.

El gato no divertido
fuente
¡Gracias! que S(i)representa
highBandWidth
El nodo sucesor. Entonces, en la iteración uno del árbol derecho, S (9) = 10, S (10) = 11, S (11) = 12, S (12) = 13 y W (9) = 1, W (10) = 1 , W (11) = 1, W (12) = 1. En la iteración dos, S (9) = 11, S (10) = 12, S (11) = 13, S (12) = 13 y W (9) = 2, W (10) = 2, W (11) = 2, W (12) = 1. En la iteración tres, S (9) = 13, S (10) = 13, S (11) = 13, S (12) = 13 y W (9) = 2 + 2, W (10) = 2 + 1, W (11) = 2, W (12) = 1.
The Unfun Cat
Debe imaginar que todos los S (i) y W (i) se actualizan al mismo tiempo cuando intenta resolver los detalles. Esto puede ser oscuro, pero quería publicarlo porque es un problema paralelo clásico y muy cercano a lo que describiste.
The Unfun Cat