Ruta más corta (algoritmo de Dijkstra)

1. Concepto

(1) El camino más corto:

  • Gráfico sin red: el camino entre dos vértices con el menor número de aristas
  • Gráfico de red: el camino más corto entre la suma de los pesos de los bordes experimentados entre dos vértices

2. Algoritmo de Dijkstra

1. Idea

Establezca un conjunto S para almacenar los vértices que han encontrado la ruta más corta y establezca un punto de origen. La matriz dist[] almacena la distancia más corta desde el punto de origen a cada vértice, y la matriz path[] almacena la ruta más corta. El proceso básico se puede describir de la siguiente manera: (La imagen a continuación es de las notas del curso relacionadas con "Estructura de datos" por el Sr. Lazy Cat)

(1) Primero seleccione un número de punto de origen , agregue el punto de origen seleccionado a U y asigne la distancia entre el punto de origen y (directamente) otros vértices a la matriz dist[]

 (2) Seleccione la ruta más corta en el dist[] existente , agregue el vértice correspondiente a la ruta a U y actualice el valor de la distancia entre el punto de origen y otros vértices (lo que significa que puede alcanzar otros vértices a través del punto recién agregado)

(3) Repita los pasos en (2) hasta que todos los vértices se suman a U

(4) Todos los nodos se agregan a U , fin

2. Estructura de datos

(1) Estructura de almacenamiento del gráfico: estructura de almacenamiento de matriz de adyacencia ponderada

(2) Array dist[n]: Cada componente distfl representa la longitud de la ruta más corta desde el punto inicial v hasta el punto final encontrado actualmente. El estado inicial es: si hay un arco de v a vi, entonces disti es el peso en el arco; de lo contrario, establezca destilar en ∞.

(3) Array path[n]: path[i] es una cadena de caracteres que indica el camino más corto encontrado actualmente desde el punto inicial v hasta el punto final vi. El estado inicial es: si hay un arco desde V, entonces ruta[i] es 0; de lo contrario, establezca ruta[i] en -1.

(4) Array s[n]: almacena el punto de origen y el punto final generado, y su estado inicial es que solo hay un punto de origen v

3. Implementación del código

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_VERTEX 10//最大的顶点个数
#define INT_MAX_ 100000
typedef int DataType;
int findMinDist(int *dist, int *s, int vertexNum);

void MGraph(DataType *vertex, int arc[][MAX_VERTEX], int vertexNum, int arcNum) { //初始化构造图(邻接矩阵法)
	printf("请逐个输入顶点的内容:");
	DataType x;
	DataType vi, vj, ave; //构建邻接矩阵时,一条边的两个结点编号
	for (int i = 0; i < vertexNum; i++) { //顶点数组赋值
		scanf("%d", &x);
		vertex[i] = x;
	}
	for (int i = 0; i < vertexNum; i++) //初始化邻接矩阵
		for (int j = 0; j < vertexNum; j++) {
			if (i == j)
				arc[i][j] = 0;
			else
				arc[i][j] = INT_MAX_;//赋值正无穷
		}
	int count = 1;
	for (int i = 0; i < arcNum; i++) { //依次输入每一条边
		printf("请输入第%d条边依附的两个顶点的编号(方向->)和权值:", count++);
		scanf("%d %d %d", &vi, &vj, &ave); //输入该边依附的顶点的编号
		arc[vi][vj] = ave; //赋值权值
	}
}

void Dijkstra(int arc[][MAX_VERTEX], int vertexNum, int startV, int *s, int *dist, int *path) {
	for (int i = 0; i < vertexNum; i++) {
		dist[i] = arc[startV][i]; //初始化数组dist,path
		if (dist[i] != INT_MAX_)
			path[i] = startV; //将原点设为上一条路径
		else
			path[i] = -1;
	}
	for (int i = 0; i < vertexNum; i++) {
		s[i] = 0;
	}
	arr(dist, path, vertexNum);//验证数组内容是否正确
	s[startV] = 1; //1值代表该结点已经加入了最短路径
	int num = 1;
	int min;
	while (num < vertexNum) { //当顶点数num小于图的顶点数,即不是所有顶点加入最小路径
		min = findMinDist(dist, s, vertexNum); //dist中查找s[i]为0的最小值元素
		s[min] = 1;
		//将新生成的结点加入集合s中
		for (int i = 0; i < vertexNum; i++) {
			//修改数组dist和path
			if ((s[i] == 0) && (dist[i] > dist[min] + arc[min][i])) {
				dist[i] = dist[min] + arc[min][i]; //用已经找到的最短路径修改对应的dist
				path[i] = min; //用已经找到的最短路径修改对应的path
				arr(dist, path, vertexNum);//验证数组内容是否正确
				printf("\n");
			}
		}
		num++;
	}
}

int findMinDist(int *dist, int *s, int vertexNum) {
	int flag = 0, min, index;
	for (int i = 0; i < vertexNum; i++) {
		if (flag == 0 && s[i] == 0) {
			min = dist[i];
			index = i;
			flag = 1;
		} else if (flag == 1 && s[i] == 0 && min > dist[i]) {
			min = dist[i];
			index = i;
		}
	}
	return index;
}

void displayPath(int *dist, int *path, int *s, int startV, int vertexNum) { //打印起始点到各顶点的最短路径
	int temp;
	int patharr[vertexNum];
	int con = 0;
	for (int i = 0; i < vertexNum; i++) {
		con = 0;
		if (i != startV) {
			printf("从顶点 %d --> %d:\n", startV, i);
			if (dist[i] != INT_MAX_)
				printf("最短路径长度为:%d\n", dist[i]);
			else {
				printf("不存在与该点之间的路径!\n");

				printf("\n");
				continue;
			}
			printf("最短路径为:");
			temp = i;
			while (temp != startV) { //得改成逆序的
				patharr[con++] = path[temp];
				temp = path[temp];
			}
			con--;
			if (con == 0) {
				printf("%d ->%d\n", patharr[con], i);
			} else {
				while (con >= 0) {
					printf("%d -> ", patharr[con]);
					con--;
				}
				printf("%d\n", i);
			}
			printf("\n");
		}
	}


}

void printMGraph(DataType *vertex, int arc[][MAX_VERTEX], int vertexNum) { //输出
	printf("vertex:");
	for (int i = 0; i < vertexNum; i++) {
		printf("%d ", vertex[i]);
	}
	printf("\n");
	printf("arc:\n");
	for (int i = 0; i < vertexNum; i++) {
		for (int j = 0; j < vertexNum; j++) {
			if (j == vertexNum - 1) {
				if (arc[i][j] == INT_MAX_)
					printf("  *\n");
				else
					printf("  %d\n", arc[i][j]);
			} else {
				if (arc[i][j] == INT_MAX_)
					printf("  * ");
				else
					printf("  %d ", arc[i][j]);
			}
		}
	}

}

main() {
	DataType vertex[MAX_VERTEX];//储存所有的顶点
	int arc[MAX_VERTEX][MAX_VERTEX];//邻接矩阵,结点间的连通关系
	int vertexNum, arcNum; //顶点个数,边的个数
	printf("请输入顶点个数和边的个数:");
	scanf("%d %d", &vertexNum, &arcNum);
	MGraph(vertex, arc, vertexNum, arcNum);
	printf("输出邻接矩阵信息:\n");
	printMGraph(vertex, arc, vertexNum);
	int x;
	printf("请输入Dijkstra算法的起点:");
	scanf("%d", &x);
	int s[vertexNum], dist[vertexNum], path[vertexNum];
	Dijkstra(arc, vertexNum, x, s, dist, path);
	printf("\n");
	printf("逐个输出由起点 %d 到所有顶点的最短路径:\n", x);
	printf("\n");
	displayPath(dist, path, s, x, vertexNum);
}

void arr(int *dist, int *path, int vertexNum) {//验证输出数组,用来debug
	printf("检查数组内容:\n");
	for (int i = 0; i < vertexNum; i++) {
		printf("%d ", dist[i]);
	}
	printf("\n");
	for (int i = 0; i < vertexNum; i++) {
		printf("%d ", path[i]);
	}
	printf("\n");
}

4. Prueba de salida

gráfico de muestra:

(Dos grupos, con 0 y 1 como punto de inicio de la búsqueda de la ruta más corta respectivamente)

(1) A partir de 0

(1) A partir de 1

Principiante Xiaobai, bienvenido a corregirme si cometo errores. 

Supongo que te gusta

Origin blog.csdn.net/m0_63223213/article/details/126918214
Recomendado
Clasificación