最短路劲的概念
如果从有向图中某一顶点(起始顶点)到达另一顶点(终止顶点)的路劲不止一条,那么如何找到一条路径不止一条,那么如何找到一条路径使得此路径各边上的权值总和达到最小?
问题的提法:
-给定一个带权有向图G与起始顶点v,求从v到G中其他顶点的最短路径(每条边上都存在有意义的权值)
解决思路
-Dijkstra提出按路径长度的递增次序,逐步产生最短路径
·首先求出长度最短的一条最短路径,在参照它求出长度次短的一条最短路径,依次类推,知道从起始顶点v到其他各顶点的最短路径全部求出为止
准备工作
-辅助数组:Array<E> dist;
·dist[i]表示当前从起始顶点V0到顶点Vi的路径长度
-初始设置
·若从起始顶点V0到顶点Vi有边:dist[i]为该边上的权值
·若从起始顶点V0到顶点Vi无边:dist[i]为∞
Dijkstra算法步骤
①初始化:S←{V0 }
dist[j]←Edge[0][j],j=1,2,...,n-1;
②找出最小路径值所对应的顶点K:
dist[k] == min{dist[i] },i∈V-S;
S←SU{k};标记k顶点进入S集合
③对于每一个i∈V-S修改:
dist[i]←min{ dist[i], dist[k] + Edge[k][i] }
④判断:若S = V,则算法结束,否则转②
Dikstra算法精髓
-S集合内的顶点是已经找到最短路径的顶点
-V0到w的最短路径只能通过S集合的顶点
-dist[w]可能改变:
if(dist[u] + Edge[u,w] < dist[w])
{
dist[w] = dist[u] + Edge[u,w];
}
定义辅助数组:
-Array<int> path;
·path[i]表示当前路径上顶点i的前驱顶点
·初始化:path = { -1 };
·修改:
if(dist[u] + Edge[u,w] < dist[w])
{
dist[w] = dist[u] + Edge[u,w];
path[w] = u;
}
SharedPointer<Array<int> > dijkstra(int i,int j,const E& LIMIT)
{
LinkQueue<int> ret;
if((0 <= i) && (i < vCount()) && (0 <= j) && (j<vCount()))
{
DynamicArray<E> dist(vCount());
DynamicArray<int> path(vCount());
DynamicArray<bool> mark(vCount());
for(int k = 0;k<vCount() ;k++)
{
mark[k] = false;
path[k] = -1;
dist[k] = isAdjacent(i,k) ? (path[k]=i,getEdge(i,k)) : LIMIT;
}
mark[i] = true;
for(int k = 0;k<vCount();k++)
{
E m = LIMIT;
int u = -1;
for(int w = 0;w < vCount() ; w++)
{
if(!mark[w] && (dist[w] < m))
{
m = dist[w];
u = w;
}
}
if(u == -1)
{
break;
}
mark[u] = true;
for(int w = 0;w<vCount() ; w++)
{
if(!mark[w] && isAdjacent(u,w) && (dist[u] + getEdge(u,w) < dist[w]))
{
dist[w] = dist[u] + getEdge(u,w);
path[w] = u;
}
}
}
LinkStack<int> s;
s.push(j);
for(int k = path[j];k!=-1;k=path[k])
{
s.push(k);
}
while(s.size() > 0)
{
ret.add(s.top());
s.pop();
}
}
else
{
//抛出异常
}
if(ret.length() < 2)
{
//抛出异常
}
return toArray(ret);
}
总结:
-Dijkstra最短路径算法是基于递推的思想完成
-起始顶点到其他各顶点的最短路径通过动态推导得到
-未标记顶点的最短路径只能由已标记顶点计算得出
-算法的最终结果是起始顶点到其他各顶点的最短路径