最短路径(Dijkstra算法)

人有一个特点,一个字就是懒,纵观世界上的交通发展史,从步行到马车,再到自行车,汽车,再到飞机、轮船火箭,归咎到底就是人想要更快更便捷的到达自己想去的地方,除了交通工具的升级,当然人们也在探索“最短路径”,最短路径问题是组合优化领域的经典问题之一,他广泛用于计算机科学、交通工程、通信工程等领域。

在进行了离散数学的学习之后我又去查阅了迪杰斯特拉(Dijkstra)算法的资料,Dijkstra算法是由荷兰科学家迪克斯特拉在1959年提出,从一个顶点到其余各顶点的最短路径算法,主要特点是以起始点为中心向外层层扩展,直到扩展到终点。

Dijkstra算法具体的原理我将从一个实际问题出发来解释。

假设我放假要出去玩,我发誓要逛遍所有日照市的海洋公园、海滨公园、香河公园、兴海公园,但是我必须先去海洋公园或者海滨公园,因为他俩太抢手,然后再从海洋公园去香河公园,或兴海公园,但是由于今天修路,海洋公园到兴海公园的路没了,通过这些需求,我在百度地图画了画路线,是这样子的:

地图

通过简化得到酱紫的图像:

线图

对图像进行标准化并剔除海滨公园到香河公园较长的路线,经过美化得到如下图:

简化美化图

接下来问题就转换成了从“1”分别到“2”,“3”,“4”,“5”的最短路径,首先我们先用数据结构存储图的信息:

3.9 6.5
3.5 12.3
10.6 12
3.7

我们还需要一个一维数组"arr"来存储“1”号顶点到其余各个顶点的初始路程,即:

1 2 3 4 5
arr 0 3.9 6.5

通过上述表格我们发现由“1”到“2”和“3”分别是3.9和6.5最近的是点“2”,因此点“2”确定:

1 2 3 4 5
arr 0 3.9

接下来从“2”发现到“3”最近,因此“3”点确定:

1 2 3 4 5
arr 0 3.9 7.4 16.2

即:

1 2 3 4 5
arr 0 3.9 7.4

接下来从"3"到"4"和"5"发现"4"较近即"4"确定:

1 2 3 4 5
arr 0 3.9 7.4 18 19.4

即:

1 2 3 4 5
arr 0 3.9 7.4 18

最后从“4”到“5”:

1 2 3 4 5
arr 0 3.9 7.4 18 21.7

即Dijkstra算法算是贪心算法实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离。

来自百度百科代码实现:

#include

#include

#define max1 10000000  //原词条这里的值太大,导致溢出,后面比较大小时会出错

int a[1000][1000];

int d[1000];//d表示源节点到该节点的最小距离

int p[1000];//p标记访问过的节点

int i, j, k;

int m;//m代表边数

int n;//n代表点数

int main()

{

    scanf("%d%d",&n,&m);

    int    min1;

    int    x,y,z;

    for(i=1;i<=m;i++)

    {

        scanf("%d%d%d",&x,&y,&z);

        a[x][y]=z;

        a[y][x]=z;

    }

    for( i=1; i<=n; i++)

        d[i]=max1;

    d[1]=0;

    for(i=1;i<=n;i++)

    {

        min1 = max1;

        //下面这个for循环的功能类似冒泡排序,目的是找到未访问节点中d[j]值最小的那个节点,

        //作为下一个访问节点,用k标记

        for(j=1;j<=n;j++)

            if(!p[j]&&d[j]d[k]+a[k][j])

                d[j]=d[k]+a[k][j];

    }

    //最终输出从源节点到其他每个节点的最小距离

    for(i=1;i",d[i]);

    printf("%d\n",d[n]); 

    return 0;

}