El algoritmo de Dijkstra para encontrar el camino más corto (súper súper detallado) se actualiza constantemente

Dijkstra encuentra el camino más corto


Problema del camino más corto

Inserte la descripción de la imagen aquí
Déjame hablar primero de la versión simple

Algoritmo de Dijkstra

El algoritmo de Dijkstra (Dijkstra) fue propuesto por el informático holandés Dijkstra en 1959, por lo que también se denomina algoritmo de Dijkstra. Es el algoritmo de ruta más corta de un vértice a los otros vértices y resuelve el problema de la ruta más corta en el gráfico de la derecha. La principal característica del algoritmo de Dijkstra es que parte del punto de partida y adopta la estrategia del algoritmo codicioso. Cada vez que atraviesa el nodo adyacente del vértice más cercano al punto de partida y no ha sido visitado hasta que se expande hasta el punto final.

Primero veamos cómo encontrar la distancia más corta del punto 1 al punto n.

Proceso de implementación

Inserte la descripción de la imagen aquí

Código
int Dijkstra()
{
    
    
    memset(dist,0x3f,sizeof dist);//除1号结点外,其他均初始为无穷大
    dist[1]=0;
    for(int i=0;i<n;i++) //n次迭代,每次寻找不在s中距离最近的点t
    {
    
    
        int t=-1;// 便于更新第一个点
        for(int j=1;j<=n;j++)
          if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
        st[t]=true;  //将t加到s中
        for(int j=1;j<=n;j++)  //用t更新其他点的距离
          dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    if(dist[n]==0x3f3f3f3f) return -1; //路径不存在
    else return dist[n];
}

Luego dale la plantilla
La
complejidad del tiempo del algoritmo dijkstra ingenuo es O (n ^ 2 + m), n representa el número de puntos, m representa el número de lados

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    
    
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
    
    
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

Bien, veamos una pregunta modelo. La práctica es el único criterio para probar la verdad.

AcWing 849. Dijkstra encuentra el camino más corto I

Dado un gráfico dirigido con n puntos y m bordes, puede haber múltiples bordes y auto-bucles en el gráfico, y todos los pesos de los bordes son positivos.
Encuentre la distancia más corta desde el punto 1 al punto N. Si no puede caminar desde el punto 1 al punto n, salida -1.
Formato de entrada La
primera línea contiene los números enteros ny m.
Cada una de las siguientes m filas contiene tres números enteros x, y 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 Muestra un número entero, que representa la distancia más corta desde el punto 1 al punto n.
Si la ruta no existe, se emite -1.
El rango de datos es
1≤n≤500,
1≤m≤105,
y la longitud del lado involucrado en la figura no excede 10000.
Muestra de entrada:
3 3
1 2 2
2 3 1
1 3 4
Muestra de salida:
3

Código completo
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int g[N][N];    //稠密图用邻接矩阵存储比较节省空间
int dist[N];    //dist[i] i结点到起始点(1号结点)的距离
bool st[N] ;    //st[i] 用于标记i结点的最短路是否确定,若确定st[i]=true;
int n,m;
int Dijkstra()
{
    
    
    memset(dist,0x3f,sizeof dist);//除1号结点外,其他均初始为无穷大
    dist[1]=0;
    for(int i=0;i<n;i++) //n次迭代,每次寻找不在s中距离最近的点t
    {
    
    
        int t=-1;// 便于更新第一个点
        for(int j=1;j<=n;j++)
          if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
        st[t]=true;  //将t加到s中
        for(int j=1;j<=n;j++)  //用t更新其他点的距离
          dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    if(dist[n]==0x3f3f3f3f) return -1; //路径不存在
    else return dist[n];
}
int main()
{
    
    
    scanf("%d%d",&n,&m);
    memset(g,0x3f,sizeof g);   //邻接矩阵的初始化,由于求的是最小值,因此初始为无穷大
    while(m--)
    {
    
    
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        g[x][y]=min(g[x][y],z); //重边中去取最小值
    }
    printf("%d\n",Dijkstra());
    return 0;
}

Si no entiende algo, no se preocupe, mire hacia abajo

Colección de preguntas frecuentes

  1. ¿Por qué 0x3f está bien cuando se asigna un valor, memset(dist,0x3f,sizeof dist)pero cuando se verifica más tarde, debe ser if(dist[n]==0x3f3f3f3f)y no una if(dist[n]==0x3f)
    respuesta ? : Se memsetinicializa por byte, int contiene 4 bytes, por lo que el valor después de la inicialización es 0x3f3f3f3f.
  2. Por qué memset(dist,0x3f,sizeof dist)inicializar la
    respuesta: 0x3f3f3f3f decimal es 1061109567, 1e9 es el nivel (magnitud y 0x7fffffff, 0x7fffffff representa el valor máximo del int de 32 bits), y los datos en el caso general son menores que 1e9, por lo que Se puede utilizar como infinito sin que los datos sean mayores que infinito. Por otro lado, dado que los datos generales nunca son mayores que 10 ^ 9, cuando agregamos infinito a un dato, no se desbordará (esto satisface "infinito más un número finito sigue siendo infinito") De hecho 0x3f3f3f3f+0x3f3f3f3f=2122219134, esto es muy grande pero no excede el rango de representación de 32 bits int, por lo que 0x3f3f3f3ftambién satisface nuestras necesidades de "infinito más infinito o infinito".
  3. for(int i=0;i<n;i++) { t=-1 }Por qué esto tdebería evaluar para -1
    responder: Porque cada vez que encontramos todos los puntos aún no se determina la distancia más corta, la distancia hasta este punto en el punto más corto. t = - 1Está stconfigurado para la conveniencia de encontrar el primer punto en este conjunto para actualizar.
  4. Si es para preguntar ¿cómo cambiar la distancia más corta de a a b? (Buena pregunta)
    Respuesta: Se usará al inicializar dist[a]=0y al regresar return dist[b].
  5. ¿Los auto-bucles y los bordes dobles afectan el algoritmo de Dijkstrea?
    Respuesta: El ciclo automático no tiene ningún efecto en la versión ingenua del algoritmo de dijkstra, por lo que el peso del ciclo automático puede ser cualquier número, siempre que no sea un número negativo. Para los bordes pesados, tomamos el valor mínimo de los bordes pesados, que es el código g[x][y]=min(g[x][y],z).
  6. ¿Por qué utilizar una matriz de adyacencia para el almacenamiento en lugar de una lista de adyacencia?
    Respuesta: Ya sea que usemos la matriz de adyacencia o la lista de adyacencia para representar el gráfico, debemos juzgar si un gráfico es un gráfico disperso o denso. Un gráfico denso se refiere al número de bordes | E | cerca de | V | ², y un gráfico disperso se refiere al número de bordes | E | es mucho menor que | V | ² (mucha diferencia de magnitud). Esta pregunta se refiere a los gráficos densos. Obviamente, los gráficos densos se almacenan en una matriz de adyacencia para ahorrar espacio y viceversa.

Las preguntas se actualizarán continuamente, deje un mensaje en el área de comentarios.

Supongo que te gusta

Origin blog.csdn.net/weixin_45629285/article/details/109406455
Recomendado
Clasificación