现实生活中,我们常常会面临者对路径选择的决策问题。例如来到一个陌生的城市,面对着纷繁交错的地铁网图,该如何进行选择可能成为一个大问题。
了解如何计算图的最短路径可能带来更为便捷的选择方式。对于非网图来说,由于没有权值,所谓的最短路径其实就是指两顶点之间经过的边数最少的路径;而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。显然,研究网图的最短路径更有实际意义。
求网图的最短路径有两种方式,分别是 算法和 算法。
Dijkstra算法
算法思想:以起始点为中心向外层层扩展,直到扩展到终点为止。就比如说我们要求
的最短路径,我们是一步步求出两个顶点之间顶点的最短路径,例如先把
或者
的最短路径求出,基于这个已求出的最短路径,求出该点到e的最短路径.
算法实现过程
(1) 一个完整的图(邻接矩阵) ,一个 数组存储路径(该顶点最短路径的前驱),一个 数组存储对应的顶点最短路径,一个 数组标记该顶点是否已求最短路径
(2) 首先进行初始化, 数组除源点外都初始化为0表示都未求, 数组初始化为源点的邻接矩阵行即 ; 数组都初始化为0
(3) 然后开始循环,共循环
次,分别对应源点到各个顶点的最短路径;通过比较
与
的大小找到离源点最近的顶点,下标为
;通过比较
与
的大小来更新当前的最短路径,即
=
;
(4) 继续第三步的步骤,直到找完所有的最短路径为止
算法实现
直接根据上面的实现过程具体实现
(1) 准备:
#define MAXVEX 100
#define INFINITY 65535
int path[MAXVEX];
int cost[MAXVEX];
int map[MAXVEX][MAXVEX];
(2) 初始化操作:
int i, j, k, min;
int final[MAXVEX]; //标记顶点
for (i = 0; i < n; ++i) {
final[i] = 0;
cost[i] = map[start][i]; //start表示源点下标
path[i] = 0;
cost[0] = 0;
final[start] = 1;
}
(3) 关键步骤:
for (i = 1; i < n; ++i) {
min = INFINITY;
//找到v0到vk的最短路径
for (j = 0; j < n; ++j) {
if (!final[j] && cost[j] < min) {
k = j;
min = cost[j];
}
}
final[k] = 1; //标记该顶点
//修正当前最短路径及距离
for (j = 0; j < n; ++j) {
if (!final[j] && min + map[k][j] < cost[j]) {
cost[j] = min + map[k][j];
path[j] = k;
}
}
}
(4) 完整实现:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
#define MAXVEX 100
#define INFINITY 65535
int path[MAXVEX];
int cost[MAXVEX];
int map[MAXVEX][MAXVEX];
char vex[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' };
void Dijkstra(int map[][MAXVEX], int start, int n) {
int i, j, k, min;
int final[MAXVEX];
for (i = 0; i < n; ++i) {
final[i] = 0;
cost[i] = map[start][i];
path[i] = 0;
cost[0] = 0;
final[start] = 1;
}
for (i = 1; i < n; ++i) {
min = INFINITY;
//找到v0到vk的最短路径
for (j = 0; j < n; ++j) {
if (!final[j] && cost[j] < min) {
k = j;
min = cost[j];
}
}
final[k] = 1;
//修正当前最短路径及距离
for (j = 0; j < n; ++j) {
if (!final[j] && min + map[k][j] < cost[j]) {
cost[j] = min + map[k][j];
path[j] = k;
}
}
}
}
int main() {
int n,m;
int i,j,k,costvalue;
ifstream in("input.txt");
in >> n >> m;
//构建图
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
map[i][j] = INFINITY;
}
}
for (k = 0; k < m; ++k) {
in >> i >> j >> costvalue;
map[i][j] = costvalue;
map[j][i] = costvalue;
}
Dijkstra(map, 0, n);
//打印最短路径
for (i = 1; i < n; ++i) {
if (path[i] == 0) {
cout << vex[0] << "->" << vex[i] << "=" << cost[i] << endl;
}
else {
vector<int> vec(n, 0);
int t = 0;
int k = i;
while (path[k] != 0) {
vec[t] = k;
k = path[k];
++t;
}
vec[t] = k;
++t;
for (int l = t; l > 0 ; --l) {
cout << vex[vec[l]] << "->";
}
cout << vex[vec[0]] << "=" << cost[i] << endl;
}
}
return 0;
}
9 15
0 1 10
0 5 11
1 2 18
1 6 12
1 7 12
2 3 22
2 7 8
3 4 20
3 6 24
3 7 21
3 8 16
4 5 26
4 8 7
5 6 17
6 8 19
a->b=10
a->b->c=28
a->b->h->d=43
a->f->e=37
a->f=11
a->b->g=22
a->b->h=22
a->b->g->i=41
通过 算法可以解决从某个源点到其余各个顶点的最短路径问题。从循环嵌套可以得到此算法的时间复杂度为