Figura - el camino más corto -Dijkstra sus variantes

camino más corto

El problema del camino más corto:

La figura Dado cualquier G(V,E)y punto de partida S, el punto T final, cómo encontrar el camino más corto desde S a T.

método común para resolver el camino más corto no

  • el algoritmo de Dijkstra
  • Algoritmo de Bellman-Ford
  • algoritmo SPFA
  • algoritmo de Floyd

A continuación se resumen principalmente Dijkstra algoritmo y sus variantes.

el algoritmo de Dijkstra

ALGORITMO

el algoritmo de Dijkstra se utiliza para resolver la fuente única problema del camino más corto , es decir, dada una gráfica G, y el punto de partida s, por el menor algoritmo distancia S cada otro vértice.

Dijkstra algoritmo es la idea básica :

Para la Figura G (V, E) dispuesto Set S, vértices almacenados han sido visitados, y luego seleccionar el mínimo y la distancia más corta entre cada punto s a partir de un vértice (denotado u) del conjunto de VS, el acceso a la colección y S. Después de eso, hacer vértice u como un punto intermedio, el punto de partida s para optimizar la distancia más corta desde todos los vértices u puede alcanzar. Esta operación se realiza n (n es el número de vértices) hasta que cuaje ya S contiene todos los vértices.

estrategia detallada:

En primer lugar establecer el conjunto S ha sido visitada vértices almacenados, entonces n veces (número de vértices) siguientes dos pasos

  1. De cada conjunto de V - seleccionar un punto de partida s y distancia de vértice más corto (denominado U) S, el acceso a la colección y S
  2. Orden vértice u es un punto intermedio entre la distancia mínima entre todos los vértices alcanzables desde u V

realización

En el proceso de implementación, hay dos cuestiones principales a considerar:

  • Para conseguir el conjunto S
  • S llegada empezando vértice V I distancia más corta (0 <= i <= n -1) se
  1. Un conjunto S puede VIS bool array [se consigue], es decir, cuando vis [i] == true tiempo de vértices V I ha sido visitada
  2. D matriz de modo int [] representa el origen de los vértices de V I distancia más corta, además del punto de partida inicial s cuando el d [s] = distinto de 0, los vértices restantes de un gran número Ode

Pseudo-código de la siguiente manera:

void Dijkstra(G, d[], s) {
    初始化;
    for(循环n次) {
       u = 使 d[u] 最小的,还未访问的顶点标号;
       记录 q 被访问;
       for(从u出发能够到达的所有顶点v){
         if(v未被访问 && 以u为中介点使得s到v的最短距离d[v]更优) {
           优化d[v];
         }
       }
    }
}

versión matriz de adyacencia

const int MAXV = 1000;  // 最大顶点数
const int INF = 1e9;        // INF很大的数字

int n, G[MAXV][MAXV];       // n 为顶点数,MAXV为最大顶点数
int d[MAXV];                        // 起点到达各点的最短路径长度
bool vis[MAXV] = {false};   // 是否被访问过

// s 为起点
void Dijkstra(int s) {
        fill(d, d+MAXV, INF);   // 初始化距离为最大值
    d[s] = 0;
    for(int i = 0; i < n; i++) {    // 重复 n 次
      int u = -1, MIN = INF;
      
      // 遍历找到未访问顶点中 d[] 最小的
      for(int j = 0; j < n; j++) {
        if(vis[j] == false && d[j] < MIN) {
          u = j;
          MIN = d[j];
        }
      }
      
      if(u == -1) return;   // 找不到小于 INF 的 d[u],说明剩下的顶点和起点 s 不连通
      vis[u] = true;    // 标记 u 为已访问
      for(int v = 0; v < n; v++) {
        // 如果v未访问 && u 能到达 v && 以 u 为中介点可以使 d[v] 更优
        if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) {
          d[v] = d[u] + G[u][v];
        }
      }
    }  
}

complejidad de tiempo: el bucle exterior O (V), el bucle O interior (V), v enumeración necesita O (V), la complejidad global es O (V * (V + V)) = O (V 2 ).

Versión lista de adyacencia

struct Node {
  int v, dis;   // v 为目标顶点,dis 为边权
};
vector<Node> Adj[MAXV]; //图G,Adj[u]存放从顶点 v 出发可以到达的所有顶点
int n;  // n为顶点数
int d[MAXV];    // 起点到达各点的最短路径长度
bool vis[MAXV] = {false};

void Dijkstra(int s) {// s 为起点
  fill(d, d+MAXV, INF);
  d[s] = 0; // 到自身为 0
  for(int i = 0; i < n; i++) {  // 循环 n 次
    int u = -1, MIN = INF;
    
    // 遍历找到未访问顶点中 d[] 最小的
      for(int j = 0; j < n; j++) {
        if(vis[j] == false && d[j] < MIN) {
          u = j;
          MIN = d[j];
        }
      }
      
      if(u == -1) return;   // 找不到小于 INF 的 d[u],说明剩下的顶点和起点 s 不连通
      vis[u] = true;    // 标记 u 为已访问
    
    // 和邻接矩阵不同
    for(int j=0; j < Adj[u][j].size(); j++) {
      int v = Adj[u][j].v;  // 获得u能直接到达的顶点
      // v 未访问 && 以 u 为中介点到达 v 比 d[v] 更短
      if(vis[v] == false && d[u] + Adj[u][j].dis < d[v]) {
        // 更新
        d[v] = d[u] + Adj[u][j].dis;    
      }
    } 
  }
}

Cuando un sujeto está borde no dirigida (lado bidireccional) cuando los bordes no tienen, al igual que las dos partes hacen ningún punto en la opuesta dirigida bordes puede.

camino más corto

Hemos no en este momento cuando se trata de la forma de registrar el camino más corto, volvemos a pseudo-código, hay un paso

    for(从u出发能够到达的所有顶点v){
         if(v未被访问 && 以u为中介点使得s到v的最短距离d[v]更优) {
           优化d[v];
         }
       }

Nos registra esta información en este momento hacia abajo, se proporciona una pre[]matriz, de manera que pre[v]indica el número de vértices anteriores (nodo precursor) en la ruta más corta desde el punto de partida s al vértice v, de modo que, cuando se satisface la condición pseudo código, u puesto asignado previamente [v], en última instancia, grabó.

Pseudocódigo se convierte en:

for(从u出发能够到达的所有顶点v){
         if(v未被访问 && 以u为中介点使得s到v的最短距离d[v]更优) {
           优化d[v];
           令 v 的前驱为 u
         }
       }

Para adyacencia matriz como un ejemplo:

const int MAXV = 1000;  // 最大顶点数
const int INF = 1e9;        // INF很大的数字

int n, G[MAXV][MAXV];       // n 为顶点数,MAXV为最大顶点数
int d[MAXV];                        // 起点到达各点的最短路径长度
int pre[MAXV];  // 记录最短路径
bool vis[MAXV] = {false};   // 是否被访问过

// s 为起点
void Dijkstra(int s) {
        fill(d, d+MAXV, INF);   // 初始化距离为最大值
    d[s] = 0;
    for(int i = 0; i < n; i++) {    // 重复 n 次
      int u = -1, MIN = INF;
      
      // 遍历找到未访问顶点中 d[] 最小的
      for(int j = 0; j < n; j++) {
        if(vis[j] == false && d[j] < MIN) {
          u = j;
          MIN = d[j];
        }
      }
      
      if(u == -1) return;   // 找不到小于 INF 的 d[u],说明剩下的顶点和起点 s 不连通
      vis[u] = true;    // 标记 u 为已访问
      for(int v = 0; v < n; v++) {
        // 如果v未访问 && u 能到达 v && 以 u 为中介点可以使 d[v] 更优
        if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) {
          d[v] = d[u] + G[u][v];
          pre[v] = u; // 记录 v 的前驱结点是 u
        }
      }
    }  
}

// 输出结点
void DFS(int s, int v) {
  if(v == s) {  // 已经递归到起点 s
    printf("%d\n", s);
    return;
  }
  DFS(s, pre[v]);           // 递归访问 v 的前驱顶点 pre[v]
  printf("%d\n", v);    // 从最深处 return 回来之后输出每一层的结点号
}

Múltiple camino más corto

En este punto hemos aprendido y método para encontrar la ruta más corta de Dijkstra, pero por lo general más de una ruta más corta.

Esto entonces tiene la trayectoria más corta a través de dos o más se puede conseguir, dará a la segunda escala del título (una primera escala de distancia), requerido para seleccionar una segunda óptimas escala caminos más cortos en todo el camino.

Por lo general hay tres maneras:

  1. Cada borde para añadir un lado derecho (como el coste)
  2. Cada aumento de un punto a un punto justo
  3. Directamente se le preguntó cuántos caminos más cortos

Por estas tres preguntas, sólo tiene que añadir una nueva matriz para almacenar el borde o punto justo derecho o número de ruta más corta, y luego modificar la optimización de d[v]los pasos pueden ser.

Por estas tres cuestiones, a saber, la solución:

  1. Añadir el lado derecho. Para añadir lado derecho representa el costo, por ejemplo, con cost[u][v]representantes de gastado u-> v, el aumento de una matriz c[], de modo que menos costo desde el punto de partida s a vértice u es c [u], solamente la inicialización c[s] = 0, el resto son para el INF (distancia El máximo). A continuación d[u] + G[u][v] < d[v], la actualización d[v]y c[v], cuando d[u] + G[u][v] == d[v]y c[u]+cost[u][v] < c[v]actualización c[v].
for(int v = 0; v < n; v++) {
        // 如果v未访问 && u 能到达 v && 以 u 为中介点可以使 d[v] 更优
        if(vis[v] == false && G[u][v] != INF) {
          if(d[u] + G[u][v] < d[v]) {
            d[v] = d[u] + G[u][v];
            c[v] = c[u] + cost[u][v];
          }else if(d[u] + G[u][v] == d[v] && c[u] + cost[u][v] < c[v]) {
            c[v] = c[u] + cost[u][v];
          }
        }
      }
  1. Ibid., Se sustituye por un conjunto de pesos.
  2. Sólo es necesario añadir una matriz num[], de modo que el número alcanza el camino más corto desde el vértice ú s como punto de partida num[u], el tiempo de inicialización, num[s] = 1el resto es 0. Cuando d[u] + G[u][v] < d[v]el tiempo, deja num [v] hereda num [u]. Cuando d[u] + G[u][v] == d[v]el num [u] se añadió num [v] en. Código es el siguiente:
for(int v = 0; v < n; v++) {
        // 如果v未访问 && u 能到达 v && 以 u 为中介点可以使 d[v] 更优
        if(vis[v] == false && G[u][v] != INF) {
          if(d[u] + G[u][v] < d[v]) {
            d[v] = d[u] + G[u][v];
            num[v] = num[u];
          }else if(d[u] + G[u][v] == d[v] && c[u] + cost[u][v] < c[v]) {
            num[v] += num[u]; //最短距离相同时累加 num
          }
        }
      }

Para consolidar el camino más corto a través de dos preguntas:

1.003 PTA , este tema es muy vale la pena hacerlo, el algoritmo de Dijkstra para considerar tres tipos de variantes, está bien familiarizado con Dijkstra.

Dijkstra + DFS

Con el asunto de referencia Dijkstra generalmente hacer, y el caso en que una pluralidad de escala es propenso a error, una descripción más general, el método para crear plantillas --Dijkstra + DFS aquí.

En la matriz de pre algoritmo siempre mantenido camino óptimo, que es una clara necesidad en el curso del algoritmo de Dijkstra para determinar cuándo actualizar el nodo predecesor para cada nodo v pre [v]. Un método más simple es: primer registro de todo el algoritmo de ruta más corta de Dijkstra (considerando sólo la distancia), y luego selecciona una trayectoria óptima de la segunda escala en estos caminos .

  1. Uso Dijkstra algoritmo del camino más corto para registrar todas las

La necesidad de registrar todos los caminos más cortos, cada nodo presentará una pluralidad de nodos predecesores, esto se puede utilizar vector<int> pre[MAXV]al nodo tienda predecesor. Para cada nodo v es, pre [v] es un vector de longitud de la matriz variable, que se utiliza para almacenar la totalidad del precursor para producir el nodo de la ruta más corta del nodo v.

A continuación, considere el cambio de pre actualización variedad d [v] en el proceso. En primer lugar, si d[u]+G[u][v] < d[v], como se describe en puntos intermedios puede u D [v] Más preferiblemente, el precursor en este momento de modo que el nodo es v u, e incluso antes de la pre [v] se ha almacenado en una serie de nodos, donde debe ser vaciado, a continuación, añadir u, porque guardado previamente en este momento no es el camino óptimo.

if(d[u] + G[u][v] < d[v]) {
  d[v] = d[u] + G[u][v];
  pre[v].clear();
  pre[v].push(u);
}else if(d[u] + G[u][v] == d[v]) {
  pre[v].push(u);
}

Así podemos escribir el código completo de la siguiente manera:

vector<int> pre[MAXV];
// s 为起点
void Dijkstra(int s) {
        fill(d, d+MAXV, INF);   // 初始化距离为最大值
    d[s] = 0;
    for(int i = 0; i < n; i++) {    // 重复 n 次
      int u = -1, MIN = INF;
      
      // 遍历找到未访问顶点中 d[] 最小的
      for(int j = 0; j < n; j++) {
        if(vis[j] == false && d[j] < MIN) {
          u = j;
          MIN = d[j];
        }
      }
      
      if(u == -1) return;   // 找不到小于 INF 的 d[u],说明剩下的顶点和起点 s 不连通
      vis[u] = true;    // 标记 u 为已访问
      for(int v = 0; v < n; v++) {
        // 如果v未访问 && u 能到达 v && 以 u 为中介点可以使 d[v] 更优
        if(vis[v] == false && G[u][v] != INF) {
          if(d[u] + G[u][v] < d[v]) {
            d[v] = d[u] + G[u][v];
            pre[v].clear();
            pre[v].push_back(u);
          }else if(d[u] + G[u][v] == d[v]) {
            pre[v].push_back(u);
          }
        }
      }
    }  
}
  1. A través de todo el camino más corto para encontrar el mejor camino para una segunda escala.

Como el nodo precursor de cada nodo puede tener múltiples procesos, atravesando formará un árbol recursivo, podemos utilizar el DFS encontrar el camino óptimo. Cuando se recorre el árbol, cada uno tendrá un nodo de hoja que se alcance completo camino más corto, cada camino de obtener, se puede calcular el valor de la segunda escala, y hacer valor de corriente óptimo de la segunda escala en comparación Si mejor que el valor óptimo, el valor óptimo se actualiza y el camino óptimo actual cubierta por este camino.

Consideramos cómo esta función recursiva de la aplicación.

  • Como segunda escala de valor óptimo global variable de optValue
  • Grabación de la matriz camino camino óptimo (utilizado para almacenar vector)
  • grabación temporal ruta DFS atravesado temppath el nodo hoja (utilizando almacenamiento vector)

Entonces considere dos configuración función recursiva: límite recursiva y recursiva, si el nodo de acceso es un nodo hoja (a partir ST), luego la recursión alcanza la descripción límite, una ruta de almacenamiento caso TempPath, se obtiene el segundo escala valor optValue y comparar.

TempPath genera en un proceso recursivo. Mientras el acceso del nodo actual v se añade a la más posterior v temppath luego pre traverse [v] de forma recursiva, otros pre [v] de todos los nodos se completa antes de atravesar la v de más atrás temppath pop.

int optValue;
vector<int> pre[MAXV];
vector<int> tempPath, path;
int st; // 出发结点

void DFS(int v) {
  if(st == v) {
    // 递归到了出发结点
    tempPath.push(v);
    int value;
    计算路径 tempPath 上的value值
    if(value优于optValue) {
      optValue = value;
      path = tempPath;
    }
    tempPath.pop_back();    // 把刚刚加入的结点弹出来哦
    return;
  }else {
    tempPath.push_back(v);  // 把当前访问结点加入临时路径 tempPath 的最后面
    for(int i = 0; i < pre[v].size(); i++) {
      DFS(pre[v][i]);
    }
    tempPath.pop_back();
  }
}

Cuando nos encontramos con un punto o derecho lado derecho, sólo tenemos que modificar el proceso de calcular el valor de valor.

Sin embargo, nota que, en los nodos de almacenamiento en el orden inverso camino TempPath, de manera que las necesidades de nodos de acceso sea hacia atrás.

// 边权之和
int value = 0;
for(int i = tempPath.size() - 1; i > 0; i--) {
  int id = tempPath[i], idNext = tempPath[i-1];
  value += V[id][nextId];
}

// 点权之和
int value = 0;
for(int i = tempPath.size() - 1; i > 0; i--) {
  int id = tempPath[i];
  value += W[id];
}

Si necesita registrar el número de la ruta más corta, la DFS también puede estar en el proceso, cada nodo hoja alcanzando tiempo que permite la variable global se incrementa.

1.030 PTA , este problema mediante la idea de Dijkstra + DFS, se puede aprender a aprender de ella.

Puede antes PTA 1003 se combinan juntos, sustancialmente el Dijkstra en nada malo.

Pero la desventaja es que Dijkstra se encontró con pesos negativos cuando el mapa es muy débil, así que esta vez hay un nuevo algoritmo.

Supongo que te gusta

Origin www.cnblogs.com/veeupup/p/12543659.html
Recomendado
Clasificación