Serie de algoritmos de planificación de rutas: (Dijkstra)



prefacio

Esta serie de artículos registra principalmente algunos puntos de conocimiento en el proceso de aprendizaje del algoritmo de planificación de rutas; El video de aprendizaje principal proviene de "Algoritmos de la serie de seguimiento de trayectorias y planificación de rutas" de la
Universidad de Bilibili . El enlace del video es el siguiente: Enlace de video Referencia del artículo: enlace 1 , enlace dos小黎的Ally


inserte la descripción de la imagen aquí

1. Dijkstra

Introducción al algoritmo

  • El algoritmo de Dijkstra es un algoritmo de ruta más corta típico, que se utiliza para calcular la ruta más corta de un nodo a otros nodos.

caracteristica principal:

  • Se basa en el punto de partida como el centro y se expande a la capa exterior (idea de búsqueda primero en amplitud) hasta llegar al punto final.
  • El algoritmo de Dijkstra utiliza la búsqueda primero en amplitud para resolver el problema de la ruta más corta de fuente única en gráficos ponderados dirigidos o no dirigidos.

idea básica

inserte la descripción de la imagen aquí

Al calcular la ruta más corta en un gráfico a través de Dijkstra, se debe especificar el punto de inicio s (es decir, el cálculo comienza desde el punto de origen s).
Además, se introducen dos conjuntos S y U. La función de S es registrar el vértice (y la longitud del camino más corto correspondiente) que se ha calculado como el camino más corto, y U es registrar el vértice para el que aún no se ha calculado el camino más corto (y la distancia desde el vértice al camino más corto). puntos de partida).
Inicialmente, solo existe el punto inicial s en S;
hay otros vértices además de s en U, y el camino del vértice en U es "el camino desde el punto inicial s hasta el vértice".
Luego, encuentre el vértice con el camino más corto desde U y agréguelo a S;
luego, actualice el vértice en U y el camino correspondiente al vértice.
Luego, encuentre el vértice con el camino más corto desde U y agréguelo a S;
luego, actualice el vértice en U y el camino correspondiente al vértice.
...
repetir esta operación hasta haber recorrido todos los vértices.

Pasos

(1) Inicialmente, S solo contiene el punto inicial s; U contiene otros vértices excepto s, y la distancia del vértice en U es "la distancia desde el punto inicial s hasta el vértice" [por ejemplo, la distancia del vértice v en U es (s
, v), entonces s y v no son adyacentes, entonces la distancia de v es ∞].
(2) Seleccione el "vértice k con la distancia más corta" de U y agregue el vértice k a S; al mismo tiempo, elimine el vértice k de U.
(3) Actualice la distancia desde cada vértice en U hasta el punto inicial s. La razón por la que se actualiza la distancia de los vértices en U es que k se determina en el paso anterior como el vértice del camino más corto, por lo que se puede usar k para actualizar la distancia de otros vértices; por ejemplo, la distancia de (s, v) puede ser mayor que (s, v) La distancia de k)+(k,v).
(4) Repita los pasos (2) y (3) hasta que se atraviesen todos los vértices.
Simplemente mirar la teoría anterior puede ser difícil de entender.Los siguientes ejemplos ilustran el algoritmo.

2. Diagrama

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Estado inicial: S es el conjunto de vértices para los que se ha calculado el camino más corto, y U es el conjunto de vértices para los que no se ha calculado el camino más corto.

Paso 1: elija el punto de origen

Seleccione el punto de origen D para unirse al conjunto S.
En este momento, S={D(0)}, U={A(∞), B(∞), C(3), E(4), F(∞), G(∞)}. Nota: C(3) significa que la distancia desde C hasta el punto inicial D es 3; ∞ significa distancia desconocida.

Paso 2: encuentre el punto de distancia más corta, únase al conjunto S y actualice el conjunto U

Seleccione del conjunto U 距离最短的节点C
Agregue el nodo C al conjunto S y elimine C del conjunto U al mismo tiempo.
Después de la operación anterior, la distancia desde el nodo C en U hasta el punto de origen D es la más corta, por lo tanto, agregue C a S y actualice la distancia de los nodos en U al mismo tiempo. Tomando el nodo F como ejemplo, la distancia de F a D es ∞, pero después de sumar C a S, la distancia de F a D es 9=(F,C)+(C,D).
En este momento, S={D(0), C(3)}, U={A(∞), B(23), E(4), F(9), G(∞)}.

Paso 3: seleccione el punto de distancia mínima del conjunto U, únase al conjunto S y actualice el conjunto U

Agregue el nodo E a S.
Después de la operación anterior, la distancia desde el nodo E en U hasta el punto de origen D es la más corta, por lo tanto, agregue E a S y actualice la distancia de los nodos en U al mismo tiempo. Aún tomando el nodo F como ejemplo, la distancia de F a D era 9; pero después de sumar E a S, la distancia de F a D es 6=(F,E)+(E,D). Por lo tanto, actualice la distancia del punto F;
en este momento, S={D(0),C(3),E(4)}, U={A(∞),B(13),F(6),G (12) }.

Paso 4: seleccione el punto de distancia mínima del conjunto U, únase al conjunto S y actualice el conjunto U

Agregue el nodo F a S.
En este momento, S={D(0), C(3), E(4), F(6)}, U={A(22), B(13), G(12)}.

Paso 5: seleccione el punto de distancia mínima del conjunto U, únase al conjunto S y actualice el conjunto U

Agregue el nodo G a S.
En este momento, S={D(0), C(3), E(4), F(6), G(12)}, U={A(22), B(13)}.

Paso 6: seleccione el punto de distancia mínima del conjunto U, únase al conjunto S y actualice el conjunto U

Agregue el nodo B a S.
En este momento, S={D(0), C(3), E(4), F(6), G(12), B(13)}, U={A(22)}.

Paso 7: seleccione el punto de distancia mínima del conjunto U, únase al conjunto S y actualice el conjunto U

Agregue el nodo A a S.
En este momento, S={D(0), C(3), E(4), F(6), G(12), B(13), A(22)}. U={conjunto vacío}
En este punto, se calcula la distancia más corta desde el punto de origen D hasta cada nodo: A(22) B(13) C(3) D(0) E(4) F(6) G( 12 ). Es decir, la ruta óptima de D→A es D→E→F→A y la distancia más corta es 22

3. Implementación de la programación

el código se muestra a continuación:

#include<iostream>
#include<string>
using namespace std;

const int MAX = 10; //限定最大的顶点数
const int _INFINITY = 65535; //定义无穷大
class Graph
{
    
    
private:
	int vertex_num; //顶点数
	int edge_num; //边数
	int weight; //权值
	string vertex[MAX]; //顶点数组
	int edge[MAX][MAX]; //邻接矩阵
	int locate(string ch); //定位
	int *final; //标识是否已纳入最短路径,置为1表示纳入
	int *distance; //存放最短路径的权值和
	string *path;  //存放最短路径字符串

public:
	Graph(int v_n, int e_n); //构造函数
	void print_graph(); //打印邻接矩阵
	void Dijkstra(int v); //Dijkstra算法
	int Min(int *_distance, int num); //最小值
};

//定位(找到字母的下标)
int Graph::locate(string ch)
{
    
    
	int index;
	for (index = 0; index < this->vertex_num; index++)
	{
    
    
		if (this->vertex[index] == ch)
		{
    
    
			break;
		}
	}
	return index;
}

//构造函数
Graph::Graph(int v_n, int e_n) : vertex_num(v_n), edge_num(e_n)
{
    
    
	int i, j, k;
	cout << "现在请输入这" << this->vertex_num << "个顶点:" << endl;
	for (i = 0; i < this->vertex_num; i++)
	{
    
    
		cin >> this->vertex[i];
	}

	//初始化邻接矩阵
	for (i = 0; i < this->vertex_num; i++)
	{
    
    
		for (j = 0; j < this->vertex_num; j++)
		{
    
    
			if (i == j)
			{
    
    
				this->edge[i][j] = 0;
			}
			else
			{
    
    
				this->edge[i][j] = _INFINITY;
			}

		}
	}

	cout << "请依次输入边相邻的两个顶点及边的权值:" << endl;
	for (k = 0; k < this->edge_num; k++)
	{
    
    
		string first, second;
		cin >> first >> second >> this->weight;
		i = this->locate(first);
		j = this->locate(second);

		edge[i][j] = this->weight;
		//无向图
		edge[j][i] = this->weight;
	}
}

//打印
void Graph::print_graph()
{
    
    
	cout << "邻接矩阵为:" << endl;
	for (int i = 0; i < this->vertex_num; i++)
	{
    
    
		for (int j = 0; j < this->vertex_num; j++)
		{
    
    
			cout << this->edge[i][j] << "\t";
		}
		cout << endl;
	}
}

//返回最小值下标
int Graph::Min(int *_distance, int num)
{
    
    
	int index = 0, min = _INFINITY;
	for (int i = 0; i < num; i++)
	{
    
    
		if (!this->final[i] && _distance[i] < min)
		{
    
    
			min = _distance[i];
			index = i;
		}
	}
	return index;
}

//Dijkstra算法
void Graph::Dijkstra(int v)  //从源点v出发
{
    
    
	int i, j, min;
	this->path = new string[MAX];
	this->final = new int[MAX];
	this->distance = new int[MAX];
	//初始化上列数组
	for (i = 0; i < this->vertex_num; i++)
	{
    
    
		this->final[i] = 0;
		this->distance[i] = this->edge[v][i]; //初始化为源点到各t'hi点的权值大小
		if (this->distance[i] != _INFINITY)
		{
    
    
			this->path[i] = this->vertex[v] + this->vertex[i]; //当直接路径存在时,同样初始化为源点到各点的路径
		}
		else
		{
    
    
			this->path[i] = "";
		}
	}
	//初始化源点
	this->distance[v] = 0;
	this->final[v] = 1;

	//开始主循环,每次求得v到一个顶点的最短路径,所以循环次数比顶点数少一次
	for (i = 1; i < this->vertex_num; i++)
	{
    
    
		min = this->Min(distance, this->vertex_num); //求当前最小值下标
		cout << "最短路径:" << this->path[min] << "\t权值:" << this->distance[min] << endl; //输出当前最短路径
		this->final[min] = 1;
		//再次循环,修正当前最短路径及其权值和
		for (j = 0; j < this->vertex_num; j++)
		{
    
    
			//如果经过的顶点的路径比现在这条路径还短的话
			if (!this->final[j] && this->distance[j] > this->edge[min][j] + this->distance[min])
			{
    
    
				this->distance[j] = this->edge[min][j] + this->distance[min];
				this->path[j] = this->path[min] + this->vertex[j];
			}
		}
	}
	delete[]path;
	delete[]distance;
	delete[]final;
}


resultado de la operación

inserte la descripción de la imagen aquí


Resumir

El algoritmo de Dijkstra es en realidad encontrar el valor con la distancia más pequeña en el conjunto U en cada paso, ponerlo en el conjunto S y actualizar los datos en el conjunto U, y después de atravesar todos los nodos, encontrar un valor mínimo al final punto que es el camino óptimo.
Finalmente, el algoritmo puede obtener un árbol de ruta óptimo y la complejidad es más razonable: O (N ^ 2).
Los pesos de borde del algoritmo de Dijkstra son todos números positivos, por lo que no habrá ponderación negativa, por lo tanto, el punto actual con la distancia más corta no puede ser actualizado por otros puntos, es decir, se garantiza que cada verificación es el punto de distancia más corta. .
Cada vez que se selecciona un punto con una distancia más corta, se actualizan las distancias de otros puntos. Porque ir directamente a un punto determinado puede no estar tan cerca como un desvío.
Los pesos de borde del algoritmo de Dijkstra son todos números positivos. Si hay números negativos, se requiere el algoritmo de Bellman-Ford. Si desea requerir la distancia más corta entre dos puntos cualesquiera, elija el algoritmo de Floyd.
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/TianHW103/article/details/127521312
Recomendado
Clasificación