当前位置:   article > 正文

C++实现图 - 04 最短路径_形成字符串的最短路径 c++

形成字符串的最短路径 c++

数据结构与算法专栏 —— C++实现

写在前面:
今天我们来看看图论中另一个非常重要的问题 —— 最短路径,正如其名就是要再图中找到起点到终点的最短路径,这就需要不断地去比较每条边的权值。
这一讲我们将会具体介绍迪杰斯特拉算法和弗洛伊德算法的实现。

迪杰斯特拉算法

迪杰斯特拉算法是一个单源点的一个最短路径算法,也就是说,我们这个算法会求得从一个顶点到其所有顶点的最短路径。

这个算法需要用到邻接矩阵来存储所有边值,并且需要一个辅助数组来更新最短路径,需要一个路径数组存储最短路径的结点,还需要一个状态数组来判断当前结点是否已经加入最短路径。

这样说可能会有点晕,我们还是先来看图,假设有这样一张图:

在这里插入图片描述

现在,我们要找到结点 0 到结点 8 的最短路径,步骤如下:

辅助数组 D:存储结点 0 到当前结点的最短路径权值。
路径数组 P:存储当前最短路径到该点的父结点。
状态数组 Final :记录当前结点是否已经加入到最短路径当中(0 代表还没有加入,1 代表已经加入)。

第一步:初始化我们上述提到的三个数组,将结点 0 加入数组中,并更新辅助数组即结点 0 连出去的边的权值。

在这里插入图片描述

第二步:找到当前辅助数组中的边权最小值,即结点 0 到结点 1 ,故加入结点 1 ,并且更新结点 1 连出去的边值。
可以发现之前更新过结点 2 的辅助数组,现在又需要更新,因为结点 0 到结点 2 的最短路径不再是 0 -> 2 ,而是 0 -> 1 -> 2 ,即最短路径值从 5 变为 1+3 = 4 ,并且结点 2 的 P 不再是 0 ,它在最短路中要先经过结点 1 ,故 P 改成 1 。

在这里插入图片描述

第三步:更上面一样,找到结点 2 加入最短路,并且更新。

在这里插入图片描述

第四步:找到结点 4 加入最短路,并且更新。

在这里插入图片描述

第五步:找到结点 3 加入最短路,并且更新。

在这里插入图片描述

第六步:找到结点 5 加入最短路,并且更新。

在这里插入图片描述

第七步:找到结点 6 加入最短路,并且更新。

在这里插入图片描述

第八步:找到结点 7 加入最短路,并且更新。

在这里插入图片描述

第九步:到达终点,生成最短路径。

在这里插入图片描述

全部代码

#include <bits/stdc++.h>
using namespace std;
#define MaxVertices 100	//假设包含的最大结点数
#define MaxWeight 99999	//假设两点不邻接的正无穷值

/*
9
16
0 1 1
0 2 5
1 2 3
1 3 7
1 4 5
2 4 1
2 5 7
3 4 2
4 5 3
3 6 3
4 6 6
4 7 9
5 7 5
6 7 2
6 8 7
7 8 4
*/

//定义邻接矩阵
struct AdjMarix {
	int Edge[MaxVertices][MaxVertices] = { 0 };
	int numV;	//当前顶点的个数
	int numE;	//当前边的个数
};

//构建图
void CreatGraph(AdjMarix *G) {
	int vi, vj, w;
	cout << "请输入顶点数量:" << endl;
	cin >> G->numV;
	for (int i = 0; i < G->numV; i++) {
		for (int j = 0; j < G->numV; j++) {
			G->Edge[i][j] = MaxWeight;
		}
	}
	cout << "请输入边的数量:" << endl;
	cin >> G->numE;
	cout << "请输入边的信息:" << endl;
	for (int i = 0; i < G->numE; i++) {
		cin >> vi >> vj >> w;
		G->Edge[vi][vj] = w;
		G->Edge[vj][vi] = w;
	}
}

//迪杰斯特拉算法
void Dijkstra(AdjMarix &M, int v0, int *P, int *D) {
	//初始化
	int Final[MaxVertices] = { 0 };
	for (int i = 0; i < M.numV; i++) {
		P[i] = -1;
		D[i] = M.Edge[v0][i];
	}
	//加入结点V0
	D[v0] = 0;
	Final[v0] = 1;
	
	int k = v0;
	for (int i = 0; i < M.numV; i++) {
		int MIN = MaxWeight;	//找到目前数组中权值最小的一条边
		for (int j = 0; j < M.numV; j++) {
			if (Final[j] == 0 && D[j] < MIN) {
				MIN = D[j];
				k = j;
			}
		}
		Final[k] = 1;	//标记该结点已经加入最短路径中
		for (int w = 0; w < M.numV; w++) {
			if (Final[w] == 0 && (MIN + M.Edge[k][w] < D[w])) {
				D[w] = MIN + M.Edge[k][w];	//更新最小值
				P[w] = k;	//记录路径(说明最短路径中到w的要经过k)
			}
		}
	}
}

int main() {
	AdjMarix AM;
	CreatGraph(&AM);
	int P[MaxVertices], D[MaxVertices];
	Dijkstra(AM, 0, P, D);
	cout << "V0到各个结点的最短路径:" << endl;
	for (int i = 0; i < AM.numV; i++) {
		cout << "V" << i << ":";
		int j = i;
		while (j != -1) {
			cout << "V" << j << "->";
			j = P[j];
		}
		cout << "V0	【最短路径为" << D[i] << "】" << endl;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

在这里插入图片描述

弗洛伊德算法

这个算法相对于上一个就十分暴力了,直接三层循环,遍历所有情况,每次都去试图找到一个中间结点,判断是否能使结点 i 到结点 j 经过结点 k 能缩短路径长度。这里我就直接展示代码啦,因为实质算法三层循环就搞定了。

#include <bits/stdc++.h>
using namespace std;
#define MaxVertices 100	//假设包含的最大结点数
#define MaxWeight 99999	//假设两点不邻接的正无穷值

/*
9
16
0 1 1
0 2 5
1 2 3
1 3 7
1 4 5
2 4 1
2 5 7
3 4 2
4 5 3
3 6 3
4 6 6
4 7 9
5 7 5
6 7 2
6 8 7
7 8 4
*/

//定义邻接矩阵
struct AdjMarix {
	int Edge[MaxVertices][MaxVertices] = { 0 };
	int numV;	//当前顶点的个数
	int numE;	//当前边的个数
};

//创建图
void CreatGraph(AdjMarix *G) {
	int vi, vj, w;
	cout << "请输入顶点数量:" << endl;
	cin >> G->numV;
	for (int i = 0; i < G->numV; i++) {
		for (int j = 0; j < G->numV; j++) {
			if (i == j) {
				G->Edge[i][j] == 0;
			} else {
				G->Edge[i][j] = MaxWeight;
			}
		}
	}
	cout << "请输入边的数量:" << endl;
	cin >> G->numE;
	cout << "请输入边的信息:" << endl;
	for (int i = 0; i < G->numE; i++) {
		cin >> vi >> vj >> w;
		G->Edge[vi][vj] = w;
		G->Edge[vj][vi] = w;
	}
}

//弗洛伊德算法
void Floyd(AdjMarix &M, int P[][MaxVertices], int D[][MaxVertices]) {
	for (int i = 0; i < M.numV; i++) {
		for (int j = 0; j < M.numV; j++) {
			P[i][j] = j;
			D[i][j] = M.Edge[i][j];
		}
	}
	//遍历所有结点所有边并更新,找到最短路径
	for (int i = 0; i < M.numV; i++) {
		for (int j = 0; j < M.numV; j++) {
			for (int k = 0; k < M.numV; k++) {
				int temp = (D[j][i] == MaxWeight || D[i][k] == MaxWeight) ? MaxWeight : D[j][i] + D[i][k];
				if (temp < D[j][k]) {
					D[j][k] = temp;
					P[j][k] = P[j][i];
				}
			}
		}
	}
	cout << "最小路径:" << endl;
	for (int i = 0; i < M.numV; i++) {
		for (int j = 0; j < M.numV; j++) {
			cout << P[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
	cout << "最小路径值:" << endl;
	for (int i = 0; i < M.numV; i++) {
		for (int j = 0; j < M.numV; j++) {
			printf("%2d ", D[i][j]);
		}
		cout << endl;
	}
}

int main() {
	AdjMarix AM;
	CreatGraph(&AM);
	int P[MaxVertices][MaxVertices], D[MaxVertices][MaxVertices];
	Floyd(AM, P, D);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

在这里插入图片描述

如果大家有什么问题的话,欢迎在下方评论区进行讨论哦~

【上一讲】图 - 03 最小生成树
【下一讲】图 - 05 拓扑排序

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/243623
推荐阅读
相关标签
  

闽ICP备14008679号