图论之最短路径算法

Posted zhongzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论之最短路径算法相关的知识,希望对你有一定的参考价值。

简介:
求最短路径算法中最具代表性的是Dijkstra算法。
Dijkstra算法的思想是基于贪心策略的。
概述其过程是通过设置顶点集合S并不断地做贪心选择来扩充集合。
贪心选择的标准是每次都选择从源节点到该节点的路径长度最短。
 
难点:
网络上博客中大多数人写的最短路径算法大多都是只能寻找到最短的一条路径。
但是很多时候可能存在并列最短的路径,需要找出所有同时最短的路径。
在这里我给大家分享一个时间复杂度大概是O(n2)的算法,求并列最短路径算法。
 
求出一条最短路径的算法步骤如下:
假设G={V,E}
1. 初始时令 S={V0},T=V-S={其余顶点},dist[当前节点] = v0到当前节点之间权重,pre[当前节点]=v0
2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中
3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值dist[Vi]=新值,Pre[Vi]=w
4. 重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
 
代码实现:
int arcs[10][10];//邻接矩阵
int D[10];//保存最短路径长度
int p[10][10];//路径
int final[10];//若final[i] = 1则说明 顶点vi已在集合S中
int n = 0;//顶点个数
int v0 = 0;//源点
int v,w;
void ShortestPath_DIJ()
{
     for (v = 0; v < n; v++) //循环 初始化
     {
          final[v] = 0; D[v] = arcs[v0][v];
          for (w = 0; w < n; w++) p[v] = v0;//设空路径     
     }
     D[v0] = 0; final[v0]=0; //初始化 v0顶点属于集合S
     //开始主循环 每次求得v0到某个顶点v的最短路径 并加v到集合S中
     for (int i = 1; i < n; i++)
     {
          int min = MAX;
          for (w = 0; w < n; w++)
          {
               //我认为的核心过程--选点
               if (!final[w]) //如果w顶点在V-S中
               {
                    //这个过程最终选出的点 应该是选出当前V-S中与S有关联边
                    //且权值最小的顶点 书上描述为 当前离V0最近的点
                    if (D[w] < min) {v = w; min = D[w];}
               }
          }
          final[v] = 1; //选出该点后加入到合集S中
          for (w = 0; w < n; w++)//更新当前最短路径和距离
          {
               /*在此循环中 v为当前刚选入集合S中的点
               则以点V为中间点 考察 d0v+dvw 是否小于 D[w] 如果小于则更新
               比如加进点3则若要考察 D[5]是否要更新就判断d(v0-v3) + d(v3-v5)的和是否小于D[5]
               */
               if (!final[w] && (min+arcs[v][w]<D[w]))
               {
                    D[w] = min + arcs[v][w];
                    p[w] = v;
               }
          }
     }
}
 
 
求出多条并列最短路径的算法步骤如下:
假设G={V,E},设置Pre数组为二维数组。
代码实现:
function shortestPath(sourceIndex, targetIndex, nodesNumber){
var v,w;
var prev = [];
var dist = [];
var MAX = Infinity;
//初始化dist和prev
for(v=0;v<nodesNumber;v++){
  visited[v] = 0;
  dist[v] = arcs[sourceIndex][v]?arcs[sourceIndex][v]:MAX;
  prev[v] = [];
}
for(v=0;v<nodesNumber;v++){
  for(w=0;w<nodesNumber;w++){
    if(v==sourceIndex){
      prev[sourceIndex][w] = arcs[sourceIndex][w]==1?1:-1;
    }else{
      prev[v][w] = -1;
    }
  }
}
dist[sourceIndex] = 0;
visited[sourceIndex] = 1;
//从T中选取一个与S中顶点有关联边且权值最小的顶点W
for(var i=0;i<nodesNumber;i++){
  var min = MAX;
  for(w=0;w<nodesNumber;w++){
    if(!visited[w] && dist[w]<min){
      v = w;
      min = dist[w];
    }
  }
  var W = [];
  for(w=0;w<nodesNumber;w++){
    if(!visited[w] && dist[w]==min){
      W.push(w);
      visited[w] = 1;
    }
  }
  //从V0到Vi的距离值缩短,则修改此距离值
  for(w=0;w<nodesNumber;w++){
    for(var j=0;j<W.length;j++){
      v = W[j];
      if(!visited[w] && min+arcs[v][w]<=dist[w]){
        dist[w] = min + arcs[v][w];
        prev[v][w] = 1;
      }  
    }
  }
 }
}
//搜索路径函数
function searchPath(v,u){
  var isConnect = false;
  for(var i=0;i<prev[v].length;i++){
    if(prev[v][i] == 1){
      if(i==targetIndex){
        path.push(targetIndex);
        paths.push(path);
        path = [sourceIndex];
        return true;
      }else{
        path.push(i);
      }
      isConnect = searchPath(i,u);
    }
  }
  if(!connect){
    path.pop();
    return false;
  }
}

以上是关于图论之最短路径算法的主要内容,如果未能解决你的问题,请参考以下文章

图论算法之最短路径

HDU 4318 图论之最短路变形

贪心算法之最短路径(Dijkstra算法)

数据结构之最短路径 [迪杰斯特拉算法]

leetcode之最短路径+记忆化dfs+bfs+动态规划刷题总结

贪心算法之最短路径