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; }
时间: 2024-10-12 14:36:33