Dijkstra single source 最短路径算法 带路径

话不多说 , 先给出Dijkstra算法的核心思想:
Dijkstra算法采用的是一种贪心的策略,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:
T,初始时,原点 s 的路径权重被赋为 0 (dis[s] = 0)。
若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为arc[s][m]
同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大。
初始时,集合T只有顶点s。
然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中,OK,此时完成一个顶点,
然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。
然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点。
参考文章:https://blog.csdn.net/qq_35644234/article/details/60870719

为了记录最佳路径轨迹,记录路径上每个节点的前趋,通过回溯法找出最短路径轨迹。
实际上这里的回溯法是指从其余顶点出发,不断的通过 前趋节点,往源点回溯。如源点为1 :
2 (0点 的前趋是 2)
1 (1点 的前趋是 1)
1 (2点 的前趋是 1)
2 (3点 的前趋是 2)
3 (4点 的前趋是 3)
6 (5点 的前趋是 6)
1 (6点 的前趋是 1)

那么从 1 到 4 需要经过哪些点呢? 4->3->2->1 即按照前趋节点的数组,就可以得到

为什么要替换更短的路径呢?其实是动态规划算法的应用。。具体还需探究。不过,这就是经典的Dijkstra算法。动态规划 的 必要条件是 最优子结构,在这题中就是:
假设A B C D G F 是A——>F 的一条最短路径 ,那么 可以断定 在这个集合中的任何子集都是一条 最短路径。反证法:假设B ->D < B->C->D 那么,最短路径就应该是 A B D G F,与已知 的最短路径矛盾。

那么,Dijkstra算法中的 S(最短路径点集) 初始只有 源点,在第一轮之后 会有 与源点直接相连的 最近点加入 S ,这是因为从其他路径到达不可能比 直接到更短,因为在初始的时候其他路径就比直达更长,比如
这里写图片描述

上面这幅图片只是第一轮 循环的过程,而更新后的 dis [],里的 min 依旧是一样的问题。

void shortestPath(int src, int dest)
    {//这里采用的是 Dijkstra 算法  假设有7个点
        int dis[7] = {0}; //定义dis为 源点到其他点的距离数组,
        //定义 path[i] 为 从 src 到 第 i 个景点的 最短路径
        int prev[7]={0}; 
        //定义 前趋节点的数组, prev[i]=num 表示 i 点 的前趋为 num 
        vector<string> shortpath(7);
        for (int i = 0; i < graph->vexNum; i++)
        {
            path[i]=src;//将所有 点的前趋 默认定义为  源点,
            shortpath.at(i).append((graph->vexs[src].name+"->"+graph->vexs[i].name).c_str());
            if (i == src)
            {
                dis[i] = 0;
                continue;
            }
            if (graph->adjMatrix[src][i] != 0)
                dis[i] = graph->adjMatrix[src][i];
            else
                dis[i] = INT_MAX;
            isWalked[i] = false;
        }
        isWalked[src] = true;

        for (int j = 0; j < graph->vexNum; j++)
        {
            int min = INT_MAX;
            int index = 0; //用这个 下标 去表征 dis中最短的路径下标
            for (int i = 0; i < graph->vexNum; i++)
            {
 //在更新完一轮最短距离时 , 再次寻找到的 min 依旧是 整个途中 距离源点最短的点
                if (min > dis[i] && isWalked[i] == false)
                {
                    if (dis[i] == 0)
                        continue; //0 表示就是 源点
                    min = dis[i];//min 选取 到达其他点目前最小的 距离
                    index = i;
 //得到这个顶点是要和 其他所有点比较src->index->i的距离是否小于src->i的
                }
   //将这个距离 源点 未访问过的点中 最近的点 加入到 最短路径点集中,并且在下面更新一波其他点的 dis 距离

            isWalked[index] = true;

            for (int i = 0; i < graph->vexNum; i++)
            {
                if ((graph->adjMatrix[index][i] + dis[index] < dis[i]) && isWalked[i] == false && graph->adjMatrix[index][i] != 0)
                {

                    dis[i] = graph->adjMatrix[index][i] + dis[index];
                    prev[i]=index;
     //由于找到了 更短的路径,,那么很明显 index节点就是 i 的前趋节点
                    int j=0;
                    for(;j<shortpath.at(index).size();j++){
                        if(shortpath.at(index).at(j)==shortpath.at(i).at(j)){
                        //对比两个 路径相同的部分,

                        }
                        else{
                            break;
                        }
                    }
                    string replace=shortpath.at(index).substr(j,shortpath.at(index).length());//replace == 两条路径不同的地方
                    shortpath.at(i).replace(shortpath.at(i).find(graph->vexs[i].name),graph->vexs[i].name.length(),replace+"->"+graph->vexs[i].name);
  //路径 到 i 被 另外一条更短的路径替代,  所以记录的 Path 也要跟着 被 替代 
  // 将 shortpath.at(index)  与 shortpath.at(i)  的相同部分舍去  不同部分 代替进 shortpath.at(i)
                }

            }

        }

        /*还差一个  最短路径的 轨迹图*/

        for(int i=0;i<7;i++)

        cout<<shortpath.at(dest)<<endl;
        cout << "最短路径长度为:" << dis[dest] << endl;
    }     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值