最短路径
对于网图来说,最短路径是指两顶点之间经过的边上的权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。
下面主要介绍两种解决最短路径的算法:
- 迪杰斯特拉(Dijkstra)算法:主要从某个源点到其余各顶点的最短路径问题。时间复杂度为O(n^2)
- 弗洛伊德(Floyd)算法:主要用来解决从所有顶点到所有顶点间的最短路径问题。时间复杂度为O(n^3)。
1.迪杰斯特拉(Dijkstra)算法
下面从一个例子开始:
例:用迪杰斯特拉算法对下列网图求顶点1到各顶点的最短路径。
其邻接矩阵为:
数组Dis用来表示顶点1到各顶点的最短距离,Fin数组用来记录已求出最短路径的顶点,如果已求出最短路径则为1,否则为0。
算法过程如下:
- 顶点1到自身的距离为0,因此给Fin[0]为1表示顶1已经求出到自身的最短距离。它到各点的最短距离暂时放在Dis数组中。
- 顶点1所能到达顶点为顶点2和顶点3,权值分别为1和12。此时知道顶点1到顶点2的最短距离为1,将顶点2对应的Fin[1]设置为1表示已经求出顶点1到顶点2的最短距离。顶点2到顶点3的距离为9,9+1<12,因此用10代替Dis[2]的值,顶点2到顶点4的值为3,3+1 = 4更新Fin[3]的值。
- 此时,在还没求出最短路径的顶点中,顶点1能到达的顶点距离最小值为4,对应顶点为4,将顶点4对应的Fin[3]设置为1表示已经求出顶点1到顶点4之间的最短距离。顶点4到顶点3的距离为4,4+4<10,因此顶点1到顶点4的最短距离为8;顶点1到顶点5的最短距离为4+13=17;顶点1到顶点6的最短距离为4+15=19。更新Dis数组。
- 接下来同上步骤,在还没求出最短路径的定点中,顶点1能到达的顶点距离最小值为4,对应顶点为3,将顶点3对应的Fin[2]设置为1表示已经求出顶点1到顶点3之间的最短距离。顶点3到顶点5的距离为5,5+8<17,因此顶点1到顶点5的最短距离为13。
-
顶点5最顶点1能到达的距离最小的顶点,将Fin[4]设置为1。顶点5到顶点6的距离为4,13+4 < 19,因此顶点1到顶点6的最短距离为17。
上述例子的代码如下:
const int m = INT16_MAX; struct Graph { int vexs[6] = {0, 1, 2, 3, 4, 5}; int arc[6][6] = { {0, 1, 12, m, m, m}, {m, 0, 9, 3, m, m}, {m, m, 0, m, 5, m}, {m, m, 4, 0, 13, 15}, {m, m, m, m, 0, 4}, {m, m, m, m, m, 0}, }; int numVex = 6, numEdg = 9; }; void ShortestPath_Dijkstra(Graph g, int v0, int D[]) { int min, k = 0; int final[6]; for (int i = 0; i < g.numVex; ++i) { final[i] = 0; D[i] = g.arc[v0][i]; } D[v0] = 0; final[v0] = 1; for (int i = 1; i < g.numVex; ++i) { min = INT16_MAX; for (int j = 0; j < g.numVex; ++j) { if (!final[j] && D[j] < min) { k = j; min = D[j]; } } final[k] = 1; for (int j = 0; j < g.numVex; ++j) { if (!final[j] && (min + g.arc[k][j] < D[j])) { D[j] = min + g.arc[k][j]; } } } } int main() { Graph g; int d[6] = {}; ShortestPath_Dijkstra(g, 0, d); for (int i = 0; i < 6; ++i) { cout << d[i] << " "; } }
从上述过程可以总结出迪杰斯特拉算法:首先找出当前点到所有能到达的点之间最短的距离,然后在已经访问过的点中遍历一遍,看看有没有更近的,如果有更近的就更新距离。然后重复上述过程就能找到最短路径。
2.弗洛伊德算法
上述例子的代码为:
const int m = INT16_MAX;
struct Graph {
int vexs[6] = {0, 1, 2, 3, 4, 5};
int arc[6][6] =
{
{0, 1, 12, m, m, m},
{m, 0, 9, 3, m, m},
{m, m, 0, m, 5, m},
{m, m, 4, 0, 13, 15},
{m, m, m, m, 0, 4},
{m, m, m, m, m, 0},
};
int numVex = 6, numEdg = 9;
};
void ShortestPath_Floyd(Graph g, int P[6][6], int D[6][6]) {
for (int i = 0; i < g.numVex; ++i) {
for (int j = 0; j < g.numVex; ++j) {
D[i][j] = g.arc[i][j];
P[i][j] = j;
}
}
for (int k = 0; k < g.numVex; ++k) {
for (int i = 0; i < g.numVex; ++i) {
for (int j = 0; j < g.numVex; ++j) {
if (D[i][j] > D[i][k] + D[k][j]) {
D[i][j] = D[i][k] + D[k][j];
P[i][j] = P[i][k];
}
}
}
}
}
int main() {
Graph g;
int d[6][6] = {};
int p[6][6] = {};
ShortestPath_Floyd(g, p, d);
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
cout << d[i][j] << "\t";
}
cout << endl;
}
}