Teoría de búsqueda y grafos (2)

ruta más corta

camino más corto de fuente única

Todos los pesos de los bordes son positivos.

Algoritmo ingenuo de Dijkstra

Idea básica: la distancia más corta desde el punto 1 a otros puntos

paso:

Defina un conjunto s que contenga los puntos con la distancia más corta actualmente determinada

1. Inicializar distancia dis[1] = 0, dis[other] = infinito positivo

2. for i 0-n bucle n veces 

    2.1 Encuentra el punto más cercano que no está en s -> t

    2.2 Sumar t a s

    2.3 Utilice t para actualizar la distancia de otros puntos

El código de la plantilla es el siguiente:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 510;
int n,m;
int g[N][N];
//dis表示从1号点到其它点的距离
int dist[N];
//st表示每个点的最短路是否确定
bool st[N];

int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;

    for(int i = 0;i < n; i ++)
    {
        int t = -1;
        for(int j = 1;j <= n;j ++)
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        st[t] = true;

        for(int j = 1;j <= n;j ++)
            dist[j] = min(dist[j],dist[t] + g[i][j]);
    }

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

    return dist[n];
}
int main()
{
    scanf("%d%d", &n, &m);

    //初始化
    memset(g,0x3f,sizeof g);

    int t = dijkstra();

    printf("%d\n",t);

    return 0;
}

Versión optimizada para el montón del algoritmo de Dijkstra

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queque>

using namespace std;

const int N = 100010;
int n,m;
//存储方式改为邻接表的形式
int h[N],w[N],e[N],ne[N],idx;
//dis表示从1号点到其它点的距离
int dist[N];
//st表示每个点的最短路是否确定
bool st[N];


void add(int a,int b,int c)
{
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}

int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;

    priority_queue<PII,vector<PII>,greater<PII>> heap;
    heap.push({0,1});
    
    while(heap.size --)
    {
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second,distance = t.first();
        if (st[ver]) continue;
        
        for(int i = h[ver];i != -1;i = ne[i])
        {
            int j = e[i];
            if(dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({dist[j],j});
            }
        }
    }
    
    if(dist[n] == 0x3f3f3f3f) return -1;

    return dist[n];
}
int main()
{
    scanf("%d%d", &n, &m);

    //初始化
    memset(h,-1,sizeof h);
    
    while(m --)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }

    int t = dijkstra();

    printf("%d\n",t);

    return 0;
}

Hay aristas ponderadas negativas.

Algoritmo de Bellman-Ford

Idea básica: n iteraciones, todos los bordes se ciclan cada vez y la distancia más corta se actualiza en cada ciclo

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int M = 100010, N = 510;

int n,m,k;
int dist[N],backup[N];

struct Edge
{
    int a,b,w;

}edges[M];

int bellman_ford()
{
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;

    for(int i = 0;i < k;i ++)
    {
        //保存上一次的结果
        memcpy(backup,dist,sizeof dist);
        for(int j = 0;j < m;j ++)
        {
            int a = edges[j].a,b = edges[j].b,w = edges[j].w;
            dist[b] = min(dist[b],backup[a] + w);
        }
    }
    if(dist[n] > 0x3f3f3f3f / 2) return -1;
    return dist[n];
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);

    for(int i = 0;i < m;i ++)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        edges[i] = {a,b,w};
    }

    int t = bellman_ford();

    if(t == -1)
    {
        puts("impossible");
    }
    else printf("%d\n",t);

    return 0;
}

Algoritmo SPFA

Una optimización del algoritmo Bellman-Ford

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queque>

using namespace std;

const int N = 100010;
int n,m;
//存储方式改为邻接表的形式
int h[N],w[N],e[N],ne[N],idx;
//dis表示从1号点到其它点的距离
int dist[N];
//st表示每个点的最短路是否确定
bool st[N];


void add(int a,int b,int c)
{
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}

int spfa()
{

    memset(dist,0x3f,sizeof dist);
   queue<int> q;

   q.push(1);
   st[1] = true;

   while(q.size())
   {
       int t = q.front();
       q.pop();

       st[t] = false;

       for(int i = h[t];i != -1;i = ne[i])
       {
           int j = e[i];
           if(dist[j] > dist[t] + w[i])
           {
               dist[j] = dist[t] + w[i];
               if(!st[j])
               {
                   q.push(j);
                   st[j] = true;
               }
           }
       }
   }

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

}
int main()
{
    scanf("%d%d", &n, &m);

    //初始化
    memset(h,-1,sizeof h);

    while(m --)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }

    int t = spfa();

    if(t == -1) puts("false");
    else printf("%d\n",t);

    return 0;
}

Ruta más corta de sumidero de múltiples fuentes

floyd

Utilice una matriz crítica para almacenar

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 210,INF = 1e9;

int n,m,Q;
int d[N][N];

void floyd()
{
    for(int k = 1;k <= n;k ++)
        for(int i = 1;i <= n;i ++)
            for(int j = 1;j <= n;j ++)
               d[i][j] = min(d[i][j],d[i][k] + d[k][j]);
}
int main()
{
    scanf("%d%d%d",&n,&m,&Q);

    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= n;j ++)
            if(i == j) d[i][j] = 0;
            else d[i][j] = INF;
    }

    while(m --)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);

        d[a][b] = min(d[a][b],w);
    }
    
    floyd();

    while(Q --)
    {
        int a,b;
        scanf("%d%d",&a,&b);

        if(d[a][b] > INF / 2) puts("impossible");
        printf("%d\n",d[a][b]);
    }

    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_64443786/article/details/132030973
Recomendado
Clasificación