Dijkstra 算法详解【容易理解】

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,具体办法是如果pU中的节点存在邻路径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为终点,若从AB的最短路径为:A----P1---P2------ Q-----B,则AQ的最短路径肯定为:A---P1---P2--------Q,即:所有最短路径中的子路径也为最短路径,即:一个最短路径是基于另一个最短路径的。

证明:若AQ的最短路径不为:A---P1---P2------Q,设:ds[Q]对应A---P1---P2------Q的路径,先ds[Q]对应另一条AQ的路径长度,且ds[Q]<ds[Q],则必有ds[B]=ds[Q]+Matrix[Q,B]<ds[Q]+Matrix[Q,B]=ds[B],则AB的最短路径不再为题设的A---P1---P2------Q---B了,与题设矛盾,故这个假设是正确的。

这个理论的正确性就使得我们建立一个从AB(B 属于U)的最短路径,就必须要基于一个从AQ(Q属于S)的路径,其中Q起到一个承接中转的作用。所以我们建立这样的一个SU的模型来求解是合理的。S集合在每次的迭代之后增加一个节点p,表示p在此次迭代之后其最优路径已经找到,U集合随之删除那个节点。

 

 

理论2:迭代都选择一个U集合中代价最小的节点p加入S中,以最优化。这里的p满足:p={p|min{dist[p]},p属于U},下面证明这个理论的正确性。

证明:每次迭代我们需要从U中选择一个点p加入S中,加入后Ap的路径可以表示为:A----------一系列点------p,根据理论1p之前的路径A---------一系列点-----)已经最优化,即:p之前的点都是位于S集合中,这个很容易理解,当然我们证明的也不是这个。我们要证明的是:

为什么选择U中目前代价最小的点加入S

我们定义:被加入S中的点其最短路径即为已经找出,即我们在目前已经了解到的信息中,可以100%确定这个是最短路径。

p1p2同为U中的两个节点:dist[p1]=14,dist[p2]=15,显然:dist[p1]<dist[p2],即:A经过Sp1目前最短的路径长度为14A经过Sp2最短的路径为15

反证法:设ds[p1]<dist[p1]=14

如果此时选择p2加入S中,则ds[p2]=dist[p2]=15,由于在p2未加入S之前,我们确定任何经过当前Sp1的路径都不是最短的,那么我们一定相信在以后会出现ASp1的长度会小于14,我们设这条路径为:A-----S中一系列点)---Q---p1ds[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,很显然(Sp1<(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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值