Dijkstra 单源点最短路径
一、理论介绍
1.概述
该算法的思想是基于集合模型的,设G=(V,E)是一个有向无环图,其中E为边的集合,值为边的权值。我们建立一个S集合和U集合用于存储一些有意义的点:
S={v|v属于V且v的最短路径已被找出(已最优)}
U={v|v属于V且v的最短路径尚未找出(待最优)}
2.解法
Dijkstra强调:
(1)*每次从U中选择一个节点加入S中,选入S的节点p满足:p在所有待选的节点集合U中其到源点的代价最小。
(2)*每次选入p之后,随即对所有U中的节点v’的代价(到源点的路径长度)进行一次更新,更新基于刚选入的节点p,具体办法是如果p到U中的节点存在邻路径Matrix(p,v’)>0,则比较原v’的代价dist[v’]和新的经过p的代价(Matrix(p,v’) + ds[p])的大小,选择min{dist[v’],Matrix[p,v’] + ds[p]}进行更新。
3.理论的正确性
理论1:设A为源点,B为终点,若从A到B的最短路径为:A----P1---P2------ Q-----B,则A到Q的最短路径肯定为:A---P1---P2--------Q,即:所有最短路径中的子路径也为最短路径,即:一个最短路径是基于另一个最短路径的。
证明:若A到Q的最短路径不为:A---P1---P2------Q,设:ds[Q]对应A---P1---P2------Q的路径,先ds’[Q]对应另一条A到Q的路径长度,且ds’[Q]<ds[Q],则必有ds’[B]=ds’[Q]+Matrix[Q,B]<ds[Q]+Matrix[Q,B]=ds[B],则A到B的最短路径不再为题设的A---P1---P2------Q---B了,与题设矛盾,故这个假设是正确的。
这个理论的正确性就使得我们建立一个从A到B(B 属于U)的最短路径,就必须要基于一个从A到Q(Q属于S)的路径,其中Q起到一个承接中转的作用。所以我们建立这样的一个S和U的模型来求解是合理的。S集合在每次的迭代之后增加一个节点p,表示p在此次迭代之后其最优路径已经找到,U集合随之删除那个节点。
理论2:迭代都选择一个U集合中代价最小的节点p加入S中,以最优化。这里的p满足:p={p|min{dist[p]},p属于U},下面证明这个理论的正确性。
证明:每次迭代我们需要从U中选择一个点p加入S中,加入后A到p的路径可以表示为:A----(------一系列点---)---p,根据理论1,p之前的路径A---(------一系列点-----)已经最优化,即:p之前的点都是位于S集合中,这个很容易理解,当然我们证明的也不是这个。我们要证明的是:
为什么选择U中目前代价最小的点加入S?
我们定义:被加入S中的点其最短路径即为已经找出,即我们在目前已经了解到的信息中,可以100%确定这个是最短路径。
设p1和p2同为U中的两个节点:dist[p1]=14,dist[p2]=15,显然:dist[p1]<dist[p2],即:A经过S到p1目前最短的路径长度为14,A经过S到p2最短的路径为15。
反证法:设ds[p1]<dist[p1]=14
如果此时选择p2加入S中,则ds[p2]=dist[p2]=15,由于在p2未加入S之前,我们确定任何经过当前S到p1的路径都不是最短的,那么我们一定相信在以后会出现A经S’到p1的长度会小于14,我们设这条路径为:A-----(S’中一系列点)---Q---p1,ds[p1]=ds[Q]+Matrix[Q,p1],Q不属于S(因为Q肯定市场在S之后才加入加来的),ds[Q]=ds[M1]+Matrix[M1,Q]=ds[M2]+Matrix[M1,M2]+Matrix[M1,Q]=......>ds[p2]
下面这个图可以更加容易帮助您理解:
此图中,如果此时不选择p1加入S中,那么以后所有的到达p1的路径都要经过此时在U中的点,即以后所有的可能的被优化的dist[p1] 都是需要先经过一个此时在U中的点,再到p1,很显然(S,p1)<(S,pi)+(pi,p1)
二、算法介绍
1.数据结构
图数据:int Graphic[N+1][N+1];//二维数组用于存储权值矩阵,下标从1开始
值:-1:断路
>0:权值
工作数据:(基于节点)
typedef struct {
int dist;// 当前的最短路径长度(is_best=true时达到最短)
int pre;//当前节点i最短路径中i对应的上节点
bool is_best;//标记节点i是否已经被最优化
}Node,*pNode;
#define N 10;
#define MAXS -1;//无穷大
2.算法描述
1.初始化数据结构://下标从1开始
pNode node=new Node[N+1];
i=1;
while(i++<=N){
node[i]->is_best=false;
node[i]->pre=s_node;
node[i]->dist=Matrix[i][s_node];
}
node[s_node]->is_best=true;//默认起点已优化
2.循环迭代
(1)选择p加入S
for(i=1;i<N;i++){
min=INT_MAX;//系统定义的最大值
if(!(node[i]->is_best) && node[i]->dist<min){
min=node[i]->dist;
p=i;
}
}
node[p]->is_best=true;
(2)在p的基础上,遍历U集合,更新dist
i=0;
while(++i<=N)
if(!node[i]->is_best && Matrix[i,p]!=MAXS && (Matrix[i,p]+min)<node[i]->dist){
node[i]->dist=Matrix[i,p]+min;
node[i]->pre=p;
}
3.输出结果:
int n_stack=new int[N];//临时数组
for(i=1;i<N;i++){
k=0;
cout<<”Node:”<<i<<”: ”<<s_node<<”->”;
j=i;
while(j!=s_node)
j=n_stack[k++]=node[j]->pre;
while(k--)
cout<<n_stack[k]<<”->”;
cout<<i<<endl;
}