任意两点间最短路问题及路径还原

1Floyd-Warshall算法

考虑用动态规划的方法,只使用顶点0~k和i,j的情况下,记i到j的最短路径为d[k][i][j]。当k=0时,只考虑i和j,即d[0][i][j]=cost[i][j].然后我们就开始讨论从k到k+1是怎样变化的。

对于顶点0~k的i到j的最短路,如果这条路径不经过第k个顶点,那么d[k][i][j]=d[k-1][i][j]。当经过第k个顶点时,d[k][i][j]=d[k-1][i][k]+d[k-1][k][j](分成两短),这样总的递推式即为d[k][i][j]=min(d[k-1][i][j]+d[k-1][i][k]+d[k-1][k][j]).

由于是三维数组,每层都要遍历所有节点,所以复杂度为O(|V|^3)。

代码如下

int d[MAX_V][dMAX_V];
int V;
void warshall_floyd{
 for(int k=0;k<V;k++
   for(int i=0;i<V;i++)
    for(int j=0;j,V;j++)
   d[i][j]=min(d[i][j],d[i][k]+d[k][j]);//二维数组不断更新即可满足递推式
 }

2路径还原

本文和上篇博客讨论了如何求最短路径,但未能还原出最短路径是怎么走的。
思路如下:我们需要找到满足d[j]=d[k]+cost[k][j]的顶点k,他是最短路上j前面的点,不断寻找就能找到最短路,时间复杂度为O(|E|)。
如果我们用一个数组记录这个点prev[j]=k,那么时间复杂度就变为O(|V|)。
给出Dijkstra算法的代码作为参考:
int cost[MAX_V][MAX_E]   
int d[MAX_V];     
bool used[MAX_V];  
int V;  
int prev[MAX_V];
void dijkstra(int s){  
  fill(d,d+V,INF);  
  fill(used,used+V,false);  
  d[s]=0;  
  while(true){  
  int v=-1;  
  for(int u=0;u<V;u++){  //从未使用的顶点中选择一个距离最小的顶点(while的第一次循环选择的是点s)  
   if(!used[u]&&(v==-1||d[u]<d[v]))   
     v=u;  
   }  
 if (v==-1) break;  
  used[v]=true;  
  for(int u=0;u<V;u++){  
    if(d[u]>d[v]+cost[v][u]){
   d[u]=d[v]+cost[v][u]; //更新和确定的点相连的点的距离  
   prev[u]=v;  //记录前面的点
    }
   }  
  }  
}  
//恢复最短路径
vector<int> get_path(int t){
  vector<int> path;
   for(;t!=-1;t=prev[t])
     path.push_back(t);
    reverse(path.begin(),path.end());  //翻转
   return path;
}

你可能感兴趣的:(最短路径)