Plantilla de ruta más corta: algoritmo de Bellman-Ford

Algoritmo de Bellman-Ford

La idea principal del algoritmo dijkstra es encontrar el punto más cercano al punto de partida sy agregarlo al conjunto determinado, y actualizar constantemente la distancia de otros puntos al punto de partida. Cada vez que se encuentra un punto, es actualizado una vez, por lo que solo se necesitan n veces. Determine la distancia más corta entre todos los puntos de partida y todos los puntos.

La función de relajación es
para cualquier borde (x, y) en el conjunto de bordes E, w (u, v) se usa para representar el peso del borde desde el vértice u al vértice v, y dis [v] es la ruta actual desde punto de partida s al vértice v Peso.
Si hay una arista (u, v) tal que: dis [v]> dis [u] + w (u, v), actualice el valor de d [v]: d [v] = d [u] + w (u, v)
Entonces, el papel de la función de relajación es determinar si pasar un vértice o pasar un cierto borde, lo que puede acortar el peso de la trayectoria desde el punto inicial hasta el punto final.

El algoritmo de Bellman-Ford no selecciona escaneando la distancia desde el vértice al punto de inicio s, sino escaneando todos los bordes cada vez y actualizando la distancia desde el punto de inicio sa todos los vértices a través de la función de relajación .

Se puede demostrar que si hay vértices no confirmados en el gráfico, después de que se relaja una iteración del conjunto de aristas, se agregará al menos un vértice confirmado , es decir, el gráficoLa longitud de un camino más cortoAgregará al menos uno.
Necesitamos encontrar el punto de partida de cada vértice.Peso del camino más corto

  1. En casos extremos, N vértices en el gráfico están todos en la ruta más corta, y la relajación de los bordes se realiza de acuerdo con el peor de los casos, es decir, solo se agrega un vértice confirmado a la vez, y el número de iteraciones que necesita a realizar es N-1;
  2. En el otro caso extremo, el margen de holgura se realiza en el mejor de los casos y el número de iteraciones a realizar es 1.

La calidad del borde de holgura depende del orden de los bordes transversales, que está relacionado con el orden de los bordes de entrada;
por otro lado, también está relacionado con la estructura del gráfico. Si se trata de una estructura de árbol como la búsqueda de unión , la iteración se puede completar una vez.

La diferencia entre la longitud de la ruta más corta y el peso de la ruta más corta:
para la ruta p <s, v1, v2, v>, el peso de la ruta es d [v] y la longitud de la ruta es 3.

Implementación de algoritmos

En la figura, el número de vértices es N, el número de aristas es M, y se conoce la distancia de sí mismo a sí mismo, que es 0. Por lo tanto, se atraviesan como máximo N-1 veces y se deben atravesar M aristas cada una tiempo, por lo que la complejidad del tiempo es O (NM).
También finaliza prematuramente, es decir, en un ciclo determinado, si no se realiza ninguna actualización después de atravesar los bordes M, significa que ha terminado antes;
además, si se atraviesa N-1 veces, aún se actualizará, indicando que hayBucle de peso negativo

Según el algoritmo de Bellman-ford, cuando se usa para encontrar la ruta más corta, no es necesario conocer la estructura del gráfico, solo se necesitan M bordes.

Consulte el algoritmo dijkstra para obtener una descripción del tema.

#include <iostream>
#include <cstring>

using namespace std;

const int N=510,M=1e5+10,INF=0x3f3f3f3f;
int dis[N];
int n,m;
struct Edge
{
    
    
    int a,b,w;
}edges[M];   //a->b的边,权值为w

void bellman_ford(int s)
{
    
    
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    
    int num=n-1;//n条边,顶点s距离已经确定,最多循环n-1遍。
    bool tag;  //判断是否提前结束的标志
    while (num--) {
    
    //最坏情况下:最多循环m-1次即可得到1号结点到每个结点的距离,这取决于遍历边的顺序
        tag=false;
        for (int i=0;i<m;i++) {
    
    
            int a=edges[i].a,b=edges[i].b,w=edges[i].w;
            //a->b 权值为w的边,确认是否修改dis[b]
            if(dis[a]!=INF && dis[b]>dis[a]+w) {
    
    
                dis[b]=dis[a]+w;   tag=true;
            }如果前驱a都没有访问到,后继b也不用发访问了,因为负权边w可能为负数,导致被替换,dis[b]!=INF(略小于)且不可达
        }                   若不存在正权边,则不用担心。
        if (!tag) break;//当不再更新边时,说明已经得到了所有顶点的最短路径,可以提前退出
    }
    
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    int a,b,w;
    for (int i=0;i<m;i++) {
    
    //循环m次,输入边的信息
        scanf("%d%d%d",&a,&b,&w);
        edges[i]={
    
    a,b,w};   //重边也进行存储,因为没法覆盖找最小值
    }
    bellman_ford(1); //求1号结点到所有结点的最短距离
    if (dis[n]==INF) puts("-1");  //输出1->n的最短距离
    else printf("%d",dis[n]);
    
    return 0;
}

Comprensión propensa a errores:
cada borde se usa más de una vez, y puede usarse muchas veces. Originalmente quería agregar una matriz bool para restringir cada borde para iterar solo una vez, pero luego descubrí que estaba mal (a, b , w) a-> b
dis[b]=min(dis[b],dis[a]+w);dis Si [b] se actualiza depende de si su predecesor dis [a] está actualizado. Si dis [a] se actualiza, dis [b] debe actualizarse, por lo que el borde (a, b) se puede utilizar repetidamente.
Esta es la idea del algoritmo spfa .

Ámbito de aplicación

El algoritmo dijkstra es adecuado para gráficos cuyos pesos de borde son todos números no negativos y pueden existir bucles.

El algoritmo bellman_ford es adecuado para bordes con pesos negativos, pero noBucle de peso negativoCaso.
Porque si hay un bucle de peso negativo en la ruta i-> j, la ruta más corta (peso) no existe.

Limitación del camino más corto: El camino más corto de
i-> j puede tener bordes de peso negativos, pero no puede haber bucles, porque si hay un bucle de peso negativo, cada vez que se pasa un bucle de peso negativo, el camino más corto será reducido una vez, si va al infinito Times, el camino más corto eventualmente será infinito negativo.

En un gráfico dirigido, los bordes ponderados negativamente no forman necesariamente un bucle ponderado negativamente;
en un gráfico no dirigido, los bordes ponderados negativamente significan bucles ponderados negativamente, por lo que no puede haber bordes ponderados negativamente en un gráfico no dirigido. (Hay i-> j, es decir, hay j-> i)

Por lo tanto, el algoritmo de Bellman-Ford puede detectar gráficos ponderados dirigidosBucle de peso negativoExistencia :
而拓扑排序可以检测有向图中是否存在回路
De acuerdo con el análisis anterior del número de ejecuciones de la función de relajación,
si no hay un bucle de peso negativo en la figura, incluso en el peor de los casos, solo se necesitan N-1 iteraciones de relajación para obtener el punto de partida para cada uno La ruta más corta del vértice;
si hay un bucle de peso negativo en el gráfico, puede realizar una función de relajación adicional, es decir, ejecutarla nuevamente después de N-1 ciclos. Si todavía hay un vértice para actualizar la distancia, significa que hay un bucle de peso negativo.

Descripción del Título

La ruta más corta con límite en el número de bordes
Dado un gráfico dirigido con n puntos ym bordes, puede haber múltiples bordes y auto-bucles en el gráfico, y los pesos de los bordes pueden ser negativos.

Encuentre la distancia más corta desde el punto 1 al punto n a través de k bordes como máximo. Si no puede caminar desde el punto 1 al punto n, la salida es imposible.

Nota: Puede haber un bucle de peso negativo en la figura.

Formato de entrada La
primera línea contiene tres números enteros n, m, k.

En las siguientes m líneas, cada línea contiene tres enteros x, y, z, lo que indica que hay un borde dirigido desde el punto x al punto y, y la longitud del lado es z.

Formato de
salida Genera un número entero, que representa la distancia más corta desde el punto 1 al punto n a través de k bordes como máximo.

Si no hay una ruta que cumpla las condiciones, se emite "imposible".

El rango de datos es
1≤n, k≤500,
1≤m≤10000, y
el valor absoluto de cualquier longitud de lado no excede 10000.

Muestra de entrada:

3 3 1 3 vértices, 3 aristas, como máximo 1 arista
1 2 1 // 1-> 2
2 3 1 // 2-> 3
1 3 3 // 1-> 3

Salida de muestra:

3

Implementación de algoritmos

Presta atención a la distinciónLongitud de la trayectoriaconPeso de la ruta

Este problema requiere encontrar el peso mínimo de la trayectoria (distancia) de 1-> n cuando la longitud máxima de la trayectoria es k.

Si el orden de atravesar los bordes relajados es: (a, b), (b, c), (c, d), (a, c), (a, d)
La primera iteración:

Realice la función de relajación en el borde (a, b), luego d [b] = d [a] + w (a, b) = 1
Realice la función de relajación en el borde (b, c), luego d [c] = d [b] + w (b, c) = 3
Realice la función de relajación en el borde (c, d), luego d [d] = d [c] + w (c, d) = 8

Este es el orden óptimo de los bordes que se deben atravesar. La distancia más corta desde el punto a hasta todos los demás puntos se puede obtener de una vez. Sin embargo, la longitud de la ruta actualizada en una iteración no es 1 y la longitud máxima de la ruta actualizada es 3: a-> b-> c-> d
Esta vez queremos restringirlo para actualizar solo la distancia más corta con una longitud de ruta de 1 en cada iteración, por lo que la medida es que el resultado de esta actualización de iteración no se aplica a esta iteración , pero a la siguiente iteración .

Por ejemplo, inicialmente, dis [a] = 0, dis [b] = dis [c] = dis [d] = INF,
cuando el borde (a, b) se relaja, dis [b] = 1, pero esta vez se actualiza Este tiempo, cuando se actualiza el borde (b, c), dis [b] todavía se actualiza de acuerdo con el último INF, pero dis [b] = 1 en la próxima actualización.

Por lo tanto, dividimos la matriz dis en dos categorías, antes de la actualización y después de la actualización. De esta manera, es posible hacer que la longitud de la ruta sea +1 para cada ciclo (la longitud de la ruta no tiene nada que ver con el peso de la ruta, y la longitud de la ruta solo está relacionada con el número de vértices pasados), de modo que k ciclos puedan cumplir con el significado de la pregunta.

Además, esto también se puede lograr tomando N-1 ciclos para recorrer la distancia desde el punto de partida a todos los vértices, pero de hecho es necesario ir N-1 veces , porque la longitud del camino entre el vértice 1 y el vértice N es N -1 (acíclico).
La pregunta solo requiere K ciclos.

En ausencia de un bucle de peso negativo ,
si K <N, puede salir del bucle while sin juzgar si necesita interrumpir de antemano, porque la matriz dis no debe haberse actualizado todavía.
Si K> = N, cuando el ciclo N, no se actualizará nuevamente, los ciclos múltiples que exceden N-1 no son válidos, por lo que ①o limite n-1 ciclos, ②o establezca la bandera cuando ya no se actualice Salga cuando se desarma .
Es decir, solo agregue una oración en la línea 18 k=min(n-1,k);.

En el caso de un bucle de peso negativo,
cuando K <N, aunque la matriz dis no se ha actualizado, puede haber pasado el bucle de peso negativo o no.
Entonces cuando K> = N, es decir, se calcula el camino más corto después del bucle con peso negativo, y cambia una vez por cada ciclo, y el número de ciclos está limitado por K.
Por tanto, la matriz dis [n] está relacionada con K y debe repetirse K veces.

Aquí, la relación entre K y N no es necesariamente. Teóricamente, debería ser K <N, pero también puede ser K> = N, y también puede haber bucles de peso negativos en la figura.
Entonces, aquí debe haber K ciclos, nok=min(n-1,k);

#include <iostream>
#include <cstring>

using namespace std;

const int N=510,M=1e4+10,INF=0x3f3f3f3f;
struct Edge
{
    
    
    int a,b,w;
}edges[M];
int dis[N],d[N];
int n,m,k;

void bellman_ford(int s)
{
    
    
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    
    while(k--) {
    
    //最多经过k条边,循环k次
        memcpy(d,dis,sizeof dis);//d数组作为旧数组存储,更新结果存在dis数组中
        for (int i=0;i<m;i++) {
    
    
            int a=edges[i].a,b=edges[i].b,w=edges[i].w;
            if(d[a]!=INF) dis[b]=min(dis[b],d[a]+w);
        }     //如果前驱都没有访问到,后继也不用发访问了,避免最后 if (dis[n] == INF ) 出现问题
    } 
    
}

int main()
{
    
    
    scanf("%d%d%d",&n,&m,&k);
    int a,b,w;
    for (int i=0;i<m;i++) {
    
    
        scanf("%d%d%d",&a,&b,&w);
        edges[i]={
    
    a,b,w};
    }
    bellman_ford(1);
    dis[n]==INF?puts("impossible"):printf("%d",dis[n]);
    
    return 0;
}

Para gráficos sin bucles de peso negativos, este método de caminar un paso a la vez y el método de caminar varios pasos a la vez pueden lograr el camino más corto desde el punto de partida a todos los vértices, pero el primero debe recorrerse N-1 veces , y el último es como máximo N-1 veces, puede haber una terminación anticipada.

Sin embargo, la ventaja del primero es que la ruta más corta se puede contar cuando la longitud de la ruta es k. (Especialmente aquellos con bucles de peso negativos)

Supongo que te gusta

Origin blog.csdn.net/HangHug_L/article/details/113946485
Recomendado
Clasificación