算法导论--单源最短路径问题(Dijkstra算法)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51918844


单源最短路径是指:给定源顶点 sV 到分别到其他顶点 vV{s} 的最短路径的问题。
Dijkstra算法采用贪心策略:按路径长度递增的顺序,逐个产生各顶点的最短路径。算法过程中需要维护一个顶点集 S ,此顶点集保存已经找到最短路径的顶点。还需要维护一个距离数组dist, dist[i]表示第i个顶点与源结点s的距离长度。


Dijkstra算法思路:

  • S初始化时只包括源节点s;
    dist[] 初始化:dist[i]= arc[s][i],arc为图的邻接矩阵。
    VS 表示未被找到最短的路径的顶点集合;

    • dist 按递增的顺序,选择一个最短路径,从 VS 把对应顶点加入到 S 中,每次S中加入一个新顶点 u , 需要对dist更新,即 s 能否通过顶点u达到其他顶点更近。
      即若dist[u] + arc[u][v] < dist[v],则更新
      dist[v]=dist[u]+arc[u][v]
    • 重复上述步骤,直到 S=V
      这里写图片描述
      这里写图片描述
      这里写图片描述

    • 代码:

      /************************************************************************
      CSDN 勿在浮沙筑高台 http://blog.csdn.net/luoshixian099算法导论--最短路径(Dijkstra算法)2016年7月15日
      ************************************************************************/
      #include <iostream>
      #include <vector>
      #include <queue>
      #include <algorithm>
      using namespace std;
      #define INFINITE 0xFFFFFFFF   
      #define VertexData unsigned int  //顶点数据
      #define UINT  unsigned int
      #define vexCounts 6  //顶点数量
      char vextex[] = { 'A', 'B', 'C', 'D', 'E', 'F' };
      
      void AdjMatrix(unsigned int adjMat[][vexCounts])  //邻接矩阵表示法
      {
          for (int i = 0; i < vexCounts; i++)   //初始化邻接矩阵
              for (int j = 0; j < vexCounts; j++)
              {
                 adjMat[i][j] = INFINITE;
              }
          adjMat[0][1] = 50; adjMat[0][2] = 10; adjMat[0][4] = 45;
          adjMat[1][2] = 15; adjMat[1][4] = 10; 
          adjMat[2][0] = 20; adjMat[2][3] = 15; 
          adjMat[3][1] = 20; adjMat[3][4] = 35; adjMat[3][5] = 3;
          adjMat[4][3] = 30; 
      }
      
      void ShortestPath_DJS(unsigned int adjMat[][vexCounts],unsigned int s)
      {
          vector<VertexData> vexset; //已经找到最短路径的顶点集
          vector<UINT> dist(vexCounts); //没有被找的最短路径的顶点距离信息
          vector<vector<VertexData> > path(vexCounts); //每个顶点的最短路径信息
          for (unsigned int i = 0; i < vexCounts; i++)
          {
              dist[i] = adjMat[s][i];  //初始化距离
              if (dist[i] != INFINITE)//s是否有路径到达i
              {
                  path[i].push_back(s);  //把保存最短路径
                  path[i].push_back(i);
              }
          }
          vexset.push_back(s); //初始把顶点s加入vexset
      
          for (unsigned int n = 1; n <= vexCounts-1; n++) 
          {
              UINT min = INFINITE;
              UINT k = INFINITE;
              for (int i = 0; i < vexCounts;i++) //寻找下一条最短路径
              {
                  if (find(vexset.rbegin(),vexset.rend(),i) == vexset.rend() && dist[i] < min)
                  {
                      k = i;
                      min = dist[i];
                  }
              }
              vexset.push_back(k); //把最短路径顶点加入vexset中
              for (int i = 0; i < vexCounts;i++)  //更新dist
              {
                  /*检测vexset中是否已经有顶点i,即i的最短路径是否已经找到。
                  如果没有找到,则判定是否需要更新最短路径*/
                  if (find(vexset.rbegin(), vexset.rend(), i) == vexset.rend() 
                      && adjMat[k][i] != INFINITE && dist[k]+ adjMat[k][i] < dist[i])
                  {
                      dist[i] = dist[k] + adjMat[k][i];
                      path[i] = path[k];
                      path[i].push_back(i);
                  }
              };
              /*便于观察,输出每个顶点的最短路径经过的所有其他顶点及其距离*/
              cout << "Path: ";
              for (int i = 0; i < path[k].size();i++)
              {
                  cout << vextex[path[k][i]] << ",";
              }
              cout << "     距离="<<dist[k]<<endl;
      
          }
      }
      
      int main()
      {
          unsigned int  adjMat[vexCounts][vexCounts] = { 0 };
          AdjMatrix(adjMat);   //邻接矩阵
          cout << "Dijkastra : A" << endl;  //计算顶点A的最短路径
          ShortestPath_DJS(adjMat, 0); //Djikstra算法,A的序号为0.
          return 0;
      }

      这里写图片描述


      Reference:
      数据结构-耿国华
      算法导论-第三版

  • 7
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,这是两个问题。让我分别回答。 --- 对于习题24.2-4,我们需要证明:对于有向图$G=(V,E)$,从源点$s$到任何其他点$v\in V$的最短路径上最多可以包含$|V|-1$条边。 我们可以使用反证法来证明这个结论。假设存在一条从$s$到$v$的最短路径包含了$|V|$条边。由于这是一条简单路径,所以它经过了$|V|$个顶点中的所有顶点。因此,这个路径形成了一个简单环。我们可以从这个简单环中删除任意一条边,得到一条从$s$到$v$的路径,路径长度比原来的最短路径长度更小,这与原来的最短路径的假设相矛盾。因此,假设不成立,结论得证。 --- 对于习题24.3-6,我们需要证明:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。 我们可以使用反证法来证明这个结论。假设存在一个从$s$到$v$的最短路径上存在一个负权重环。由于负权重环的存在,我们可以通过不断绕这个环走来无限制地减小路径长度,因此不存在从$s$到$v$的最短路径。但是,Bellman-Ford算法会在第$|V|$次松弛操作之前终止,并且在第$i$次松弛操作之后,算法会计算出从$s$到所有距离$s$不超过$i$的顶点的最短路径。因此,我们可以得出结论:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值