单源点
多源点
算法思想:
先初始化距离数组d[ ] = INF ,d[1] = 0 。
根据d[v] = min( d[u] + w[u][v] , d[v] ),对所有的边进行"松弛",值得注意,每一轮松弛都会更新至少一条最短路径,即得到一个最小的 d[i]。
时间复杂度: O(|V|*|W|)
Bellmanford(G, w, s)
{
Init(G);//初始化,包括设置距离数组d[ ],且d[s] = 0;
//进行n-1次全面“松弛”,每次至少找到了一条最短路径。
for(int i=1; i < |V|; i++){
for( (u,v) in G ){
Relax(u,v,w);
}
}
//检验是否有负权边
for( (u,v) in G ){
if( d[v] > d[u] + w[u,v] ) return false;
}
return true;
}
Relax(u,v,w){
if( d[v] > d[u] + w[u,v])
d[v] = d[u] + w[u,v]; //更新(“松弛”)距离
parent[v] = u; //记录v上一个节点
}
算法思想:
维持一个数组的d[ N ]记录各个点到源点的距离, s[ N ]记录已经访问过的点,1代表已经访问,0代表未访问。
每次从未访问的点中选出 最小的d[i] , 并对其子节点进行更行距离。通过N次选取、更行后,即完成了计算所有点到单源点的距离。其中,也可以用parent[N]数组记录父节点。
时间复杂度: n次取出, 每次查找n, 总时间O(n*n)
(思考:数组d[N]可以换成一个最优队列,每次取出最优队列的最小值,更新新的d[] 时也可以在最优队列中更新)
//伪代码:
Dijkstra(){
Init(G);
// s[ 1...N ] = {0}; s[1] = 1;
Q = V; //初始化最优队列
while( !Q.empty() ){
u =ExtractMin(Q);
for( v in Adj[u] ){
Relax(u,v,w);
}
}
}
设 i 到 j 的最短路径p 途径 k,路径p(i,j)=min (p(i,k)+w(k,j)), k=1…n 。
思考递归方程,进而可以理解动态规划思想。
即D(i,j)(m) = min( D(i,k)(m-1)+w(k,j) ), k= 1…n
D(i,j)(m)代表第m次更新矩阵
注意第m次更新矩阵,至少可以得到路径长为m的最优路径
时间复杂度: n^4
Dynamic() //动态规划
{
D(i,j)(0) = 0或者INF; //初始化距离矩阵D(0)
for( int m = 0; m<= n -1; m++)
for( int i = 1; i<= n; k++)
for( int j = 1; j<= n; k++)
for( int k = 1; k<= n; k++)
D(i,j)= min( D[i][k] + W[k][j] ,D[i][j])
return D(n);
}
…
算法思想:
找中间节点k;设 i 到 j 的最短路径p 途径 1,2,3… k。那么,若点k在p上,可以将路径p分成 p1: i***k 和 p2:k***j;
即 d(i,j) (k)= min( d(i,j) (k-1), d(i,k)(k-1)+d(k,j)(k-1) )
( d(i,j)(k) 代表点i 到 点j 途径 的点在1…k中,且d(i,j)(0) = w(i,j) )
时间复杂度:n^3
FloyWarshall()
{
D(0) = W; //初始化距离举证D(0)
for( int k = 1; k<= n; k++)
for( int i = 1; i<= n; k++)
for( int j = 1; j<= n; k++){
d(i,j) = min( d(i,j) , d(i,k)+d(k,j) )
}
return D(n);
}