目录
一、问题的论述与理解
最短路径问题是指从图中的一个顶点出发,到达另一个顶点的所有路径中,加权边权值和最小的那条路径。最短路径问题重点在于如果起点到终点的直接距离不是最短距离,如何寻找起点经过其它顶点到终点的距离使其小于起点到终点的直接距离的最优解,即最短距离。
二、算法设计
设图有N个顶点,图的邻接矩阵为figure[][n],figure[A][B]为顶点A到顶点B的距离,要求最短路径,我们可以通过dijkstra算法来解决这个问题
dijkstra算法思想是基于贪心算法思想的。所谓贪心算法即始终保持当前迭代解为当前最优解。就是在已知的条件下或是当前拥有的全部条件下保证最优解,若在此后的迭代中由于加入了新的条件使得产生了更优解则替代此前的最优解。通过不断的迭代不断保证每次迭代的结果都是当前最优解,那么当迭代到最后一轮时得到的就会是全局最优解。我们先定义一个数组dist[],用dist[i]来表示起点start到其余各顶点的最短距离,通过图的邻接矩阵将其初始化,而后通过不断更新dist[i]的值,使其真正成为起点到顶点i的最短距离,即所求的最短路径。
具体步骤:
- 利用邻接矩阵figure[][n]初始化dist[],dist[i]=figure[start][i];
- 依次找出n-1个距离起点最近的顶点k并标记,防止多次访问出现错误
- 如果起点到顶点k的距离加上顶点k到终点的距离之和小于起点到终点的直接距离,那么更新dist的值,因为有n-1个顶点k,所以需要比较n-1次,符合条件就更新dist,即 dist[k] + figure [k][i] < figure [start][i] 成立,则更新
- 重复第2、3步,直到所有顶点访问完毕
三、算法实现代码
#include<stdio.h>
#define inf 0xfffffff//无穷大
#define n 8
void initdist(int figure[][n], int dist[], int start) {
//printf("第一步:初始化dist\n");
for (int i = 0; i < n; i++) {
dist[i] = figure[start][i];
}
}
int getMindist( int dist[], int flag[]) {
//printf("第二步:查找离start最近的点\n");
int min = inf, k;
for (int i = 0; i < n; i++) {
if (flag[i] == 0 && dist[i] < min) {
min = dist[i];
k = i;
}
}
return k;
}
int getMin(int a, int b) {
return a < b ? a : b;
}
void updatedist(char f[], int figure[][n], int dist[], int flag[], int k, int start) {
//printf("第三步:更新dist\n");
for (int i = 0; i < n; i++) {
int min = getMin(dist[k] + figure[k][i], figure[start][i]);
if (flag[i] == 0 && min < dist[i]) {
dist[i] = min;
//printf("dist[k] + figure[k][i]=%d, figure[start][i]=%d\n", dist[k] + figure[k][i], figure[start][i]);
//printf("dist[k] + figure[k][i]=%d < figure[start][i]=%d成立,更新\n", dist[k] + figure[k][i], figure[start][i]);
printf("此路径更短:%c->%c->%c\n", f[start], f[k], f[i]);
}
else {
//printf("dist[k] + figure[k][i]=%d < figure[start][i]=%d不成立,不更新\n", dist[k] + figure[k][i], figure[start][i]);
}
}
}
void dijkstra(char f[],int figure[][n], int dist[], int start) {
initdist(figure, dist, start);//第一步
int flag[n] = { 0 };
flag[start] = 1;
for (int i = 0; i < n-1; i++) {
int k=getMindist( dist, flag);//第二步
flag[k] = 1;
updatedist(f, figure, dist, flag, k, start);
}
}
void display(char f[], int dist[], int start) {
for (int i = 0; i < n; i++) {
printf("%c->%c最短路径=%d\n", f[start], f[i], dist[i]);
}
printf("\n");
}
void main() {
int dist[n] = { 0 };
char f[] = "ABCDEFGH";
int figure[][n] = { {0, 2, 6, 1, 8, 10, 7, 5},
{2, 0, 2, 7, 2, 1, 5, 2 },
{6, 2, 0, 4, 3, 4, 9, 7},
{1, 7, 4, 0, 10, 3, 4, 8},
{8, 2, 3, 10, 0, 5, 10, 5},
{10, 1, 4, 3, 5, 0, 7, 6},
{7, 5, 9, 4, 10, 7, 0, 10},
{5, 2, 7, 8, 5, 6, 10, 0} };
printf("--------------start=%c-------------\n", f[x]);
dijkstra(f, figure, dist, 0);
display(f, dist, 0);
}
四、测试结果与分析
--------------start=A-------------
A->A最短路径=0
A->B最短路径=2
A->C最短路径=4
A->D最短路径=1
A->E最短路径=4
A->F最短路径=3
A->G最短路径=5
A->H最短路径=4
根据测试结果可以看出,起点A到顶点C,E,F,G,H的最短路径都不是从起点到终点的直接距离,都是通过算法设计中的第3步更新后的结果,通过检验,测试结果正确无误,证明dijkstra算法的设计准确,可以有效得到正确的结果。
五、总结
最短路径问题的关键在于如何找到两点之间的最短路径。这个问题可以改写为在具有边权(权重)的图中寻找两点之间的最短路,其中边权表示路径的代价。例如,一个城市之中的街道可以用图的形式表示,每个街道可以看作是图上的一条边,而边的长度(或者权重)则表示两个位置之间的距离。
在解决最短路径问题时,关键的算法之一是Dijkstra算法。Dijkstra算法的核心思想是通过遍历图来找到起点到终点的最短路径,该算法不断将起点到每个节点的距离更新,并将已经访问的节点标记为“永久性”,直到到达终点,或者所有未访问的节点都不能到达起点时,算法停止。
在实际问题中,最短路径问题的解决可以给我们提供非常重要的信息,例如在路线规划中,人们需要了解哪个路径是最短的,以便在最短的时间内到达目的地。在网络优化中,寻找网络节点之间的最短距离可以实现网络性能优化。在商业运作中,需要通过最短路径来减少运输成本并提高运输效率。因此,解决最短路径问题的方法和技巧有着广泛的应用。
如有不当之处恳请指正