有5个城市(A,B,C,D,E),其中每个城市到其他城市的直达距离已知,两个城市之间只有一条公路。计算从城市A到其他任意城市的最短路径距离。
4行数据, 第一行是A到(B,C,D,E)的直达距离,第二行是B到(C,D,E)的直达距离,。。。,第4行是D到E的直达距离。
A城市到(B,C,D,E)的最短距离。
2 3 4 5 3 4 2 4 3 3
2 3 4 4
(1)解题思路:
利用Dijstra算法,将问题变化为一个适合贪心算法的子集选择问题。
定义M为一个城市集合:其中每个城市X,存在一条从源点A城市到X的全局最短路径,并且该最短路径不包含A之外的城市。
①(即:当城市集合M = {A}时,该题目中的初始dis[] = {0, 2, 3, 4, 5})
定义N = 全部城市-M集合,需要从N中选择一个城市X进入M集合。此时在dis[]中选择最短的路径,即min = 2, minpos = B(即哪个城市);
根据所选择的第二个点X = B,此时城市集合M = {A, B},在此时更新从A到任意一个城市是否经过B点的最短路径
②(M= {A, B}, 更新后dis[] = {0, 2, 3, 4, 4})
再在dis[]中选择最短的路径,即min = 3, minpos = C;
根据所选择的第二个点X = C,此时城市集合M = {A, B, C},在此时更新从A到任意一个城市是否经过C点的最短路径
③(M= {A, B, C},更新后dis[] = {0,2, 3, 4, 4})
再在dis[]中选择最短的路径,即min = 4, minpos = D;
根据所选择的第二个点X = D,此时城市集合M = {A, B, C, D},在此时更新从A到任意一个城市是否经过D点的最短路径
④(M= {A, B, C,D}, 更新后dis[] = {0, 2, 3, 4, 4})
再在dis[]中选择最短的路径,即min = 4, minpos = E;
根据所选择的第二个点X = E,此时城市集合M = {A, B, C, D, E},在此时更新从A到任意一个城市是否经过E点的最短路径
⑤(M= {A, B, C,D, E}, 更新后dis[] = {0, 2, 3, 4, 4})
输出答案为A→B, A→C, A→D, A→E 即(2, 3, 4, 4).
(2)其中利用的两个定理:
1.如果从u→v点的最短路径L={u, , x, , y, , v}, 则L上的子段l= (x, , y)也是最短路径。
2.所有N中的顶点中,最短的局部最短路径是全局最短路径。
(3)证明:略
代码:
#include <iostream>
#define INFINITE 0x7fffffff
using namespace std;
int main() {
int dis[5] = { 0 };
bool inM[5] = { 0 };//表示是否已进入M集合
int cost[5][5] = { 0 };
for(int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
if (i < j)
cin >> cost[i][j];
cost[j][i] = cost[i][j];
}//输入
for (int i = 0; i < 5; i++)
dis[i] = cost[0][i];//第1步的dis[]
inM[0] = 1;//第一个城市A自然是进入了M集合
for (int i = 1; i <= 4; i++)
{
int min = INFINITE;
int minpos = 0;
for(int j = 0; j < 5; j++)
if (inM[j] == 0 && dis[j] < min) {
//没有进入M集合的并且路径最短
min = dis[j];
minpos = j;
}
inM[minpos] = 1;
for(int j = 0; j < 5; j++)
if (inM[j] == 0 && dis[j] > dis[minpos] + cost[minpos][j])
dis[j] = dis[minpos] + cost[minpos][j];
//是否经过这个minpos,更新dis[]
}
for (int i = 1; i < 5; i++)
cout << dis[i] << " ";//输出
return 0;
}