狄杰斯特拉算法:单源最短路径问题

1.问题的引入:

  • 在一个图中,如何根据图中的信息,从一个单一的顶点出发,寻找其他所有顶点到这个顶点的最小值呢?并且还要求最小路径是什么。

2.算法思想:

  • 辅助定义:
    • 引入两个集合S 和V−S, 其中第一个集合用于记录已经收录的顶点(亦即已经求出最短路径的节点集合)第二个集合是该图中剩余没求得最短路径的节点集合。
    • 引入辅助向量dist[Vertax]该向量用于记录每一个顶点对应的dist值
      • 那么有小伙伴要问了:什么是dist值呢?:简单来说就是只经过集合S中的所有顶点从原点出发到这个点的最短距离叫做这个节点的dist值
      • 由此试想一下,当所有节点都收录进集合S中,是不是就意味着已经求的所有顶点的最短路径了呢?
    • 引入辅助向量path[vertax],该向量用于记录这个顶点到原点的最短路径中途中经过的顶点
      • 什么意思呢?简要回答一下,就是说比如一个顶点v最短路径中前一个顶点是w,则path[v]=w.
      • 为什么要这么做呢?因为比如已经求得所有节点的最短路径值,通过path[i]找i节点路径中前一个节点,以此直到找到原节点,以此压入栈中,然后我们从栈中以此取出这些节点对应就是i这个顶点到原点的最短路径了
  • 算法概述:
    • 首先将原点v0收录进S集合中,于是dist v0=0这个很好理解,自己到自己的距离等于0嘛
    • 重复如下过程直到在未收录节点集合V- S中找不到dist最小的值:
      1. 找到dist最小值的节点并且记录其信息为v
      2. 然后将这个节点v收录进入S中,亦即该节点的最短路径是已经求出。为什么可以这样做?
        • 假设最小dist对应节点i的dist值不是最短路径,那么必然存在其他一个节点j在V- S这个集合中,在i的最短路径上使得S中节点先到j再到i才是最短路径。但是问题来了如果该假设成立,就意味着j的dist值一定是小于i的,因为我们一直是取的未收录中最小的,那么j理应加入S集合了,但是j却不在S集合中。与假设矛盾
        • 由上述分析,每一次找到最小的dist对应的节点i我们可以放心大胆的说这个节点dist就是最短路径,因为我们按照非递减的顺序收录节点
      3. 对于刚刚收录节点v,看一圈其临边对于的节点w,如果dist[v]+Edge(v,w) <dist[w],更新dist[w]=dist[v]+Edge(v,w)
        • 关于这一步也好理解,刚刚收进去一个节点了,如果通过这个节点能够使得到相邻的其他节点的值变小,当然也就以为这其他节点的dist值要更新(关于这一点去理解一下dist定义)便很好掌握
  • 算法伪代码:
  • bool FindMin(int *d,bool *c,int& v,int length)
    //该函数是在所有还未被收录的定点中找到最小值d,然后将该节点记录在v,并返回成功与否
    {
        int Max=InF+1;
        for (int i = 0; i <length ; ++i) {
            if (!c[i]&&d[i]<Max)
            {
                v=i;
                Max=d[i];
            }
        }
        if(Max!=InF+1)
            return true;
        else
            return false;
    }
    bool DjsTra(AdjGraph& G,int v0,int* path,int* dist)
    {
        //初始化路径
        for (int i = 0; i <G.num_V ; ++i) {
            path[i]=-1;
        }
        //初始化 dist数组
        for (int i = 0; i <G.num_V ; ++i) {
            dist[i]=InF;
        }
        //已经收录的节点集合
        bool collected[G.num_V];
        for (int i = 0; i <G.num_V ; ++i) {
            collected[i]= false;
        }
        int count=0;
        dist[v0]=0;//从v0开始收录节点;
        int v_next;
        while (1) {
            if (!FindMin(dist, collected, v_next,G.num_V)) {
                break;
            }
            else
            {
                v_next=true;
                for (ArcNode* p=G.Adjlist[v_next].FirstEdge; p  ; p=p->Next) {
                    if(dist[v_next]+p->info<dist[p->vertax])
                    {
                        dist[p->vertax]=dist[v_next]+p->info;
                        path[p->vertax]=v_next;
                    }
                }//对于刚刚收录进去的节点的所有临街点看看能不能更新最小路径
            }
        }
        if (count<G.num_V)
            return false;//图不是联通图
        else
            return true;
        //函数调用完成,最短路径在dist 数组中,路径上的节点保存在path数组中
    
    }
    

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值