Algoritmo de ruta más corta de múltiples fuentes: análisis del algoritmo Floyd-Warshall

Insertar descripción de la imagen aquí

matriz de adyacencia gráfica

namespace Graph_Structure
{
    
    
	//Vertex是代表顶点的数据类型,Weight是边的权值的数据类型,MAX_W是权值的上限值(表示不相两)
	//Direction表示图是否为有向图
	template<class Vertex, class Weight = int, Weight MAX_W = INT_MAX, bool Direction = false>
	class Graph
	{
    
    
		typedef Graph<Vertex, Weight, MAX_W, Direction> Self;
	public:
		//使用编译器的默认构造函数
		Graph() = default;

		//给定一个存放顶点的数组用来初始化图
		Graph(const Vertex* a, size_t n)
		{
    
    
			_vertexs.reserve(n);
			_indexMap.rehash(n);
			_matrix.resize(n, std::vector<Weight>(n, MAX_W));
			for (size_t i = 0; i < n; ++i)
			{
    
    
				_vertexs.push_back(a[i]);
				//建立顶点和数组下标的映射(目的是为了邻接矩阵的边存储)
				_indexMap[a[i]] = i;
			}
		}

		//获取顶点在邻接矩阵中对应的下标
		size_t GetVertexIndex(const Vertex& vertex)
		{
    
    
			if (_indexMap.find(vertex) == _indexMap.end())
			{
    
    
				throw "invalued_para";
				return -1;
			}
			return _indexMap[vertex];
		}


		void _AddEdge(size_t srci, size_t dsti, const Weight& w)
		{
    
    
			//判断是有向图还是无向图
			if (Direction == false)
			{
    
    
				_matrix[dsti][srci] = w;
			}
			_matrix[srci][dsti] = w;
		}
		//给定起点和终点,在邻接矩阵中添加一条边
		void AddEdge(const Vertex& src, const Vertex& dst, const Weight& w)
		{
    
    
			if (_indexMap.find(src) == _indexMap.end() || _indexMap.find(dst) == _indexMap.end())
			{
    
    
				throw "invalued_para";
			}

			size_t srci_index = GetVertexIndex(src);
			size_t dst_index = GetVertexIndex(dst);
			_AddEdge(srci_index, dst_index, w);
		}
		
		//将图的邻接矩阵打印出来
		void Print()
		{
    
    
			for (auto e : _vertexs)
			{
    
    
				std::cout << e << '[' << _indexMap[e] << ']' << std::endl;
			}

			std::cout << "     ";
			for (int i = 0; i < _vertexs.size(); ++i)
			{
    
    
				std::cout << i << "    ";
			}
			std::cout << std::endl;


			int i = 0;
			for (auto arry : _matrix)
			{
    
    
				std::cout << i++ << ' ';
				for (auto e : arry)
				{
    
    
					if (e == MAX_W)
					{
    
    
						printf("%4c ", '*');
					}
					else
					{
    
    
						printf("%4d ", e);
					}
				}
				std::cout << std::endl;
			}
		}

		//图的广度优先遍历
		void BFS(const Vertex& src)
		{
    
    
			size_t begin = GetVertexIndex(src);
			std::queue<int> QNode;
			std::vector<bool> Label(_vertexs.size(), false);
			QNode.push(begin);
			Label[begin] = true;
			size_t Level = 0;
			while (!QNode.empty())
			{
    
    
				size_t LevelSize = QNode.size();
				for (size_t i = 0; i < LevelSize; ++i)
				{
    
    
					size_t front = QNode.front();
					QNode.pop();
					std::cout << _vertexs[front] << '[' << front << ']' << std::endl;
					for (int j = 0; j < _vertexs.size(); ++j)
					{
    
    
						if (Label[j] == false && _matrix[front][j] != MAX_W)
						{
    
    
							QNode.push(j);
							Label[j] = true;
						}
					}
				}
			}
		}
		
		//图的深度优先遍历
		void DFS(const Vertex& src)
		{
    
    
			std::vector<bool> visited(_vertexs.size(), false);
			_DFS(GetVertexIndex(src), visited);
		}
	private:
		void _DFS(size_t srci, std::vector<bool>& visited)
		{
    
    
			visited[srci] = true;
			std::cout << _vertexs[srci] << '[' << srci << ']' << std::endl;
			for (int i = 0; i < _vertexs.size(); ++i)
			{
    
    
				if (_matrix[srci][i] != MAX_W && visited[i] == false)
				{
    
    
					_DFS(i, visited);
				}
			}
		}
	private:
		std::vector<Vertex> _vertexs;						// 顶点集合
		std::unordered_map<Vertex, size_t> _indexMap;		// 顶点映射下标
		std::vector<std::vector<Weight>> _matrix;			// 邻接矩阵
	};
}

En un gráfico ponderado dirigido (puede haberCaminos con pesos negativos., pero no puede existirUn ciclo con un peso total negativo), se puede encontrar el algoritmo Floyd-Warshallentre dos vértices cualesquierael camino más corto

1. Idea del algoritmo Floyd-Warshall (basado en programación dinámica)

  • Supongamos que hay Nun vértice en el gráfico y los vértices están 0~N-1numerados de acuerdo con

  • utilizado en el algoritmoMatriz bidimensionalDistPara registrar la longitud de la ruta más corta entre puntos, Dist[i][j]indicando la longitud de la ruta más corta desde el i-ésimo vértice hasta el j-ésimo vértice,DistEl estado inicial de la matriz.paraUna copia de la matriz de adyacencia del gráfico.

  • Puede haber vértices en el camino más corto entre dos vértices cualesquiera iy :j0 ~ N-2Insertar descripción de la imagen aquí

  • Suponga que el camino más corto de vértice ia vértice esjEl vértice numerado más altoes kel vértice, el camino ientre kes y el camino entre es (no es difícil demostrar que también es el camino más corto de p1vértice a vértice y también es el camino más corto de vértice a vértice )kjp2p1ikp2kj

  • Por lo tanto hayecuación de transición de estado:Dist[i][j] = Dist[i][k] + Dist[k][j]Insertar descripción de la imagen aquí

  • La suma del camino más corto también puede p1serp2Divida las subrutas de la misma manera..Repita la división de la ruta hasta que la ruta esté dividida en componentes que ya no se puedan dividir.estado mínimo, de variosestado mínimocomenzarRealizar transferencia de estadoPuede obtener el camino más corto de vértice ia vértice j.

  • transferencia de estadomendigarEl camino más corto entre dos puntos cualesquiera.El proceso se puede completar a través del siguiente bucle:

			//动态规划求最优解
			for (int k = 0; k < _vertexs.size(); ++k)
			{
    
    
				for (int i = 0; i < _vertexs.size(); ++i)
				{
    
    
					for (int j = 0; j < _vertexs.size(); ++j)
					{
    
    
						if (Dist[i][k] != MAX_W && Dist[k][j] != MAX_W &&
							Dist[i][k] + Dist[k][j] < Dist[i][j])
						{
    
    
							Dist[i][j] = Dist[i][k] + Dist[k][j];
						}
					}
				}
			}

Insertar descripción de la imagen aquí

  • El proceso de determinar el camino más corto entre otros dos puntos es similar.

2.Interfaz del algoritmo Floyd-Warshall

		//多源最短路径算法(允许带负权路径存在)
		//Dist数组用于记录顶点间的最短路径的长度
		//ParentPath数组用于记录最短路径上某个顶点的前驱结点编号
		void FloydWarShall(std::vector<std::vector<Weight>>& Dist, std::vector<std::vector<int>>& ParentPath)
		{
    
    
			Dist.resize(_vertexs.size(), std::vector<Weight>(_vertexs.size(), MAX_W));
			ParentPath.resize(_vertexs.size(), std::vector<int>(_vertexs.size(), -1));

			//根据图的邻接矩阵初始化Dist数组
			for (int i = 0; i < _matrix.size(); ++i)
			{
    
    
				for (int j = 0; j < _matrix.size(); ++j)
				{
    
    
					if (i == j)
					{
    
    
						Dist[i][j] = 0;
					}
					else if(_matrix[i][j] != MAX_W)
					{
    
    
						Dist[i][j] = _matrix[i][j];
						ParentPath[i][j] = i;
					}
				}
			}

			//动态规划求各个最短路径
			for (int k = 0; k < _vertexs.size(); ++k)
			{
    
    
				for (int i = 0; i < _vertexs.size(); ++i)
				{
    
    
					for (int j = 0; j < _vertexs.size(); ++j)
					{
    
    
						if (Dist[i][k] != MAX_W && Dist[k][j] != MAX_W &&
							Dist[i][k] + Dist[k][j] < Dist[i][j])
						{
    
    
							Dist[i][j] = Dist[i][k] + Dist[k][j];
							//i到j最短路径上,j顶点的前驱为k到j最短路径上j的前驱
							ParentPath[i][j] = ParentPath[k][j];
						}
					}
				}
			}
		}

Apéndice de notas: Ruta más corta de fuente única: algoritmo Bellman-Ford

  • Bellman-FordEl algoritmo puede serEn un gráfico con trayectorias de peso negativas.Resuelva el problema del camino más corto desde una única fuente
  • DistSe utiliza una matriz unidimensional para registrarpunto de origen a otros vérticesLa longitud de la ruta más corta: Dist[i]representa ila longitud de la ruta más corta desde el punto de origen hasta el nodo
  • La matriz unidimensional ParentPathse utiliza para registrar el número de nodo predecesor de un determinado vértice en la ruta más corta: representa el número del nodo predecesor del nodo ParentPath[i]en la ruta más corta.i

1. Parte central de la interfaz del algoritmo Bellman-Ford

			for (int i = 0; i < _vertexs.size() - 1; ++i)
			{
    
    
				for (int j = 0; j < _vertexs.size(); ++j)
				{
    
    
					for (int k = 0; k < _vertexs.size(); ++k)
					{
    
    
						if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&
							_matrix[j][k] + dist[j] < dist[k])
						{
    
    
							dist[k] = _matrix[j][k] + dist[j];
							parentPath[k] = j;
						}
					}
				}
  • Se puede demostrar que el bucle anterior se puede atravesar.cualquier camino más corto posible.Para cualquier camino más corto,Doble circulación internaSe puede registrar al menos un borde en la ruta más corta, por lo que el bucle más externo solo necesita realizarse N-1una vez ( Nque es el número de vértices del gráfico) para atravesar todas las rutas más cortas:Insertar descripción de la imagen aquí
  • Bellman-FordEl algoritmo necesita comprobar si existe unaUn ciclo con un peso total negativo,existirUn ciclo con un peso total negativoEl gráfico no puede resolver el problema del camino más corto.

2.Interfaz del algoritmo Bellman-Ford

		//带负权路径的单源最短路径算法
		bool BellmanFord(const Vertex& src, std::vector<Weight>& dist, std::vector<int>& parentPath)
		{
    
    
			dist.resize(_vertexs.size(), MAX_W);
			parentPath.resize(_vertexs.size(), -1);

			int srci = GetVertexIndex(src);
			dist[srci] = Weight();
			bool flag = true;
			for (int i = 0; i < _vertexs.size() - 1; ++i)
			{
    
    
				for (int j = 0; j < _vertexs.size(); ++j)
				{
    
    
					for (int k = 0; k < _vertexs.size(); ++k)
					{
    
    
						if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&
							_matrix[j][k] + dist[j] < dist[k])
						{
    
    
							//经过j结点,更新源点到k结点的路径长度
							dist[k] = _matrix[j][k] + dist[j];
							parentPath[k] = j;
							flag = false;
						}
					}
				}
				if (flag)
				{
    
    
					//路径不再发生更新,则说明所有最短路径都已经确定
					return false;
				}
				flag = true;
			}

			//检验图中是否存在负权环路
			//如果存在负权环路,则Dist数组会继续被更新
			flag = false;
			for (int j = 0; j < _vertexs.size(); ++j)
			{
    
    
				for (int k = 0; k < _vertexs.size(); ++k)
				{
    
    
					if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&
						_matrix[j][k] + dist[j] < dist[k])
					{
    
    
						dist[k] = _matrix[j][k] + dist[j];
						flag = true;
					}
				}
			}
			return flag;
		}

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_73470348/article/details/132628800
Recomendado
Clasificación