¿Existe una optimización que reduzca el factor constante del tiempo de ejecución de Floyd-Warshall, si se garantiza que tiene una matriz de adyacencia simétrica?Optimice Floyd-Warshall para la matriz de adyacencia simétrica
Respuesta
Después de pensarlo se me ocurrió:
for (int k = 0; k < N; ++k)
for (int i = 0; i < N; ++i)
for (int j = 0; j <= i; ++j)
dist[j][i] = dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
Ahora, por supuesto que ambos tienen que mostrar que es correcto y rápido.
La corrección es más difícil de probar, ya que se basa en la prueba de Floyd-Warshall que no es trivial. Una buena prueba se da aquí: Floyd-Warshall proof
La matriz de entrada es symmetric. Ahora el resto de la prueba usa una prueba modificada de Floyd-Warshall para mostrar que el orden de los cálculos en los 2 bucles internos no importa y que el gráfico permanece simétrico después de cada paso. Si mostramos que ambas condiciones son verdaderas, ambos algoritmos hacen lo mismo.
Definamos dist[i][j][k]
como la distancia i
-j
usando usando sólo vértices del conjunto {0, ..., k}
como vértices intermedios en el camino i
-j
.
dist[i][j][k-1]
se define como el peso del borde desde i
hasta j
. Si no hay borde entre este peso se toma como infinito.
Ahora, utilizando la misma lógica que se utiliza en la prueba vinculado anteriormente:
dist[i][j][k] = min(dist[i][j][k-1], dist[i][k][k-1] + dist[k][j][k-1])
Ahora en el cálculo de dist[i][k][k]
(y de manera similar para dist[k][i][k]
):
dist[i][k][k] = min(dist[i][k][k-1], dist[i][k][k-1] + dist[k][k][k-1])
Ahora bien, como dist[k][k][k-1]
no puede ser negativa (O tendríamos un negative loop en el gráfico), esto significa que dist[i][k][k] = dist[i][k][k-1]
. Dado que si dist[k][k][k-1] = 0
ambos parámetros son los mismos, de lo contrario se elige el primer parámetro de min()
.
Así que ahora, debido a dist[i][k][k] = dist[i][k][k-1]
, al calcular dist[i][j][k]
no importa si dist[i][k]
o dist[k][j]
permiten ya k
en sus caminos. Como dist[i][j][k-1]
solo se usa para el cálculo de dist[i][j][k]
, dist[i][j]
se quedará dist[i][j][k-1]
en la matriz hasta que se calcule dist[i][j][k]
. Si i
o j
es igual a k
, se aplica el caso anterior.
Por lo tanto, el orden de los cálculos no es importante.
Ahora tenemos que mostrar que dist[i][j] = dist[j][i]
después de todos los pasos del algoritmo.
Comenzamos con una cuadrícula simétrica así dist[a][b] = dist[b][a]
, para todos a
y b
.
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
= min(dist[j][i], dist[k][i] + dist[j][k])
= min(dist[j][i], dist[j][k] + dist[k][i])
= dist[j][i]
Por lo tanto nuestra tarea es a la vez verdadera y que mantendrá el invariante que dist[a][b] = dist[b][a]
. Por lo tanto, dist[i][j] = dist[j][i]
después de todos los pasos del algoritmo
Por lo tanto, ambos algoritmos arrojan el mismo resultado, correcto.
La velocidad es más fácil de probar. El ciclo interno se llama poco más de la mitad del número de veces que se lo llama normalmente, por lo que la función es aproximadamente el doble de rápida. Acabo de hacer un poco más lento porque todavía asigna el mismo número de veces, pero esto no importa, ya que min()
es lo que ocupa la mayor parte de su tiempo.
Si ve algún error en mi prueba, por muy técnico que sea, indíquelo e intentaré solucionarlo.
EDIT:
Puede acelerar o ahorrar la mitad de la memoria cambiando el bucle como tal:
for (int k = 0; k < N; ++k) {
for (int i = 0; i < k; ++i)
for (int j = 0; j <= i; ++j)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[j][k]);
for (int i = k; i < N; ++i) {
for (int j = 0; j < k; ++j)
dist[i][j] = min(dist[i][j], dist[k][i] + dist[j][k]);
for (int j = k; j <= i; ++j)
dist[i][j] = min(dist[i][j], dist[k][i] + dist[k][j]);
}
}
Esto se divide lo anterior para los bucles del algoritmo optimizado, por lo sigue siendo correcto y es probable que obtenga la misma velocidad, pero usa la mitad de la memoria.
Gracias a Chris Elion por la idea.
Siéntase libre de votarme si le gustó la respuesta :) – celion
solo tenga en cuenta que los dos códigos anteriores no producen el mismo resultado experimentalmente. – WhitAngl
la primera actualización en el segundo código debe ser: dist [i] [j] = min (dist [i] [j], dist [k] [i] + dist [k] [j]); la segunda actualización debe ser: dist [i] [j] = min (dist [i] [j], dist [i] [k] + dist [k] [j]); la tercera actualización es correcta. – WhitAngl
(Usando la notación en el pseudo-código en el artículo de Wikipedia) Creo (pero no he probado) que si la matriz edgeCost es simétrica, entonces la matriz de ruta también será simétrica después de cada iteración. Por lo tanto, solo necesita actualizar la mitad de las entradas en cada iteración.
En un nivel inferior, solo necesita almacenar la mitad de la matriz (ya que d (i, j) = d (j, i)), por lo que puede reducir la cantidad de memoria utilizada y, con suerte, reducir el número de caché falla ya que accederá a los mismos datos varias veces.
- 1. Numpy matriz simétrica 'inteligente'
- 2. ¿Cómo almacenar una matriz simétrica?
- 3. Matriz de incidencia en lugar de matriz de adyacencia
- 4. Estructura de datos similar a una matriz simétrica para C++
- 5. representación de gráficos: lista de adyacencia frente a la matriz
- 6. Optimizando el código vectorizado para la adyacencia de gráficos
- 7. Lista de adyacencia y gráfico
- 8. Optimice JSonArray for Loop
- 9. reduciendo los requisitos de memoria para la lista de adyacencia
- 10. Comparando objeto gráfico representación a la lista de adyacencia y la matriz de representaciones
- 11. Si topológicamente clasifico un DAG, ¿puedo soltar la mitad de la matriz de adyacencia?
- 12. Levenshtein distancia simétrica?
- 13. Algoritmo de línea ultra simétrica?
- 14. Cómo implementar una matriz de adyacencia en Java produciendo ciclos de hamilton
- 15. estructura de lista de adyacencia en HBase
- 16. cómo representar simétrica de muchos a muchos
- 17. Algoritmo de cifrado de clave simétrica
- 18. consulta recursiva para la lista de adyacencia para preordenar el recorrido del árbol en SQL?
- 19. ¿Qué algoritmo de clave simétrica usa SSL?
- 20. R: ggplot: ¿Cómo se traza una matriz cuadrada (no simétrica) como un mapa de calor?
- 21. SSL es mitad simétrica y mitad asimétrica?
- 22. Cómo generar una matriz cuadrada simétrica real aleatorio con las entradas distribuidas uniformemente
- 23. Lista de adyacencia frente al modelo de conjunto anidado
- 24. ¿Cómo modelo una relación simétrica con django?
- 25. ¿Alguien conoce algún compilador que optimice el código de consumo de energía para dispositivos integrados?
- 26. ¿Cómo prevenir que gcc optimice algunas afirmaciones en C?
- 27. Creación de una lista de adyacencia de un data.frame
- 28. OpenSSL utilizando EVP vs API algoritmo de criptografía simétrica
- 29. La forma más eficiente de crear un árbol desde la lista de adyacencia
- 30. ¿Cómo puedo duplicar una clave simétrica de SQL Server?
¿No es siempre simétrico? O_o –
A veces puede tener bordes dirigidos, entonces no es simétrico. – JPvdMerwe