最短路 Dijkstra算法

    这是一类求单源最短路的算法,也就是求某一个顶点到其他所有顶点的最短路。它是按照最短路径递增的顺序来计算的。

   先说一下大体思路:将图中的顶点分为两个集合,S,V-S。S存储已经求出最短路径的顶点,V-S存储未求出最短路的顶点。然后算法就是不断额的求出V-S中顶点的最短路,然后把它加入S中,直到所有顶点的最短路都求出,也就是V-S是空集。

  选择邻接矩阵的数据结构来存储图。

  下面先交代一下需要引进的数据结构:

      一堆数组s[i]来记录v0到vi的最短是否已经确定。用1 0 或者true false表示;

     一堆数组Path[i]来记录vi所在当前的最短路径的vi的直接前驱。初始值:如果v0 vi之间有弧,Path[i]初始值为v0 ,否则为-1.

     一堆数组D[i],记录v0到vi的当前最短(注意是当前最短,而不是最后求出的真正的最短路的长度)路径的长度。初始值:如果v0 vi 之间有弧,D[i]为弧上的权值,否则为∞



算法核心:

      
每一次遍历寻找当前未确定最短路径的顶点到v0 的最短路中的最小值,将这条最短路的终点k加入集合s。而此时,集合s中已经有了两个顶点了,再求其他点vi的最短路的时候,就有了一个中继的顶点。就是说,可能存在D[i]>D[k]+g[k][vi]的情况,这时候就要更新D[i]也就是v0到vi的当前最短路径,并把vi的直接前驱改为vk。这个更新当前最短路的步骤被称为松弛操作。更新完毕以后再寻找当前路径中的最小值,然后再重复上述步骤。


这里我之前有一个疑惑,就是当S 集合里面多于两个顶点的时候,只考虑通过最后一次加入集合S的那个点来进行松弛操作,那其他已经加入s集合的顶点不考虑会不会错过最优解呢?嗯,,确实是自己的思维还是不够灵活。比如说,点a b c 依次加入了集合s,那么你在以C点为中继点来更新当前最短路之前,D[i]的值就已经是根据点b更新过了的,同样你在根据b更新之前的D[i]的值是已经根据a更新过了的,所以不必担心会错过最优解。呐,之所以称为更新,就是一个不断优化的过程,是吧。

    对于那个记录vi直接前驱的数组Path[i]是用来最终递归输出最短路依次经过的点的。

下面是核心代码:

for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
        {
            if(i==j)g[i][j]=0;
            else
               g[i][j]=INF;
        }//初始化邻接矩阵
        for(int i=0;i<m;i++)
        {
            cin>>a>>b>>c;
            g[a][b]=c;
        }//用邻接矩阵存储图
       for(int i=0;i<n;i++)
       {
           d[i]=g[0][i];//初始化当前最短路径
           s[i]=false;//起初顶点全部不在集合S内
       }
       s[0]=true;//将v0加入集合S
        for(int i=1;i<n;i++)
            path[i]=0;

       //算法核心语句
       int minn,v;
       for(int i=1;i<n;i++)
       {
           minn=INF;
           for(int w=0;w<n;w++)
               if(!s[w]&&d[w]<minn)
               {
                   v=w;
                   minn=d[w];
               }//寻找当前最短路径
               s[v]=true;//并将该点加入集合S
               for(int w=0;w<n;w++)
                if(!s[w]&&d[v]+g[v][w]<d[w])
               {
                   d[w]=d[v]+g[v][w];
                   path[w]=v;//更新直接前去
               }//松弛操作
       }//循环n-1次,也就是对其余 n-1个顶点进行计算





  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值