最短路径之Dijkstra算法

今天看了最短路径之Dijkstra算法,对这算法,写上自己的心得和感悟!

1.Dijkstra算法,(迪杰斯特拉)--单源最短路径

求的是一个源点到其他顶点的最短路径

算法描述

1).算法思想

设G=(V,E)是一个带权的有向图,把图中顶点集合V分成两个部分。第一个部分是    已求出的与源点的最短路径的顶点集合,   另一部是还没求出来的。第一个部分用S表示,另一部分用U表示。在U中求出剩下点中与源点最短的那个点,然后,将这个点放入S中。<<------这句话是最关键的地方,每一次放入S的前提是,这个点与源点的路径是最短的,可以这么想,我就是那个点,地处福州,现在我要去北京。在目前来讲,我要到北京,假设距离10,而,其他地方到北京的距离比10大,那我有何必要先去其他地方,然后在去北京?因此,只要保证在U中的要拿出来的顶点,一定是与S中的顶点链接起来的路径在U中最短,这样就可以保证最短路径问题了!!

 

2).算法步骤

a.初始化,S刚开始的时候只有源点V0,这么一个点,并且这个源点V0的距离是  0,V中包含的是其余的点。根据上面所说的,要拿出与S中的顶点链接起来的路径在U中最短。刚开始的只有那些,跟源点有权值的才可以,所以,建立一个dist(distance距离的意思),里面存放的是其余各个顶点跟源点V0的权值情况。如果有权值,就把权值输入,没有的话,设为最大(如果设为0 的话,那么在比较的时候就比较难办了)。当然还要有一个数组,用来表示的是各个顶点有没有被放入S中的情况。所以初始化的时候,需要2个一维数组,1个2维数组。

b.现在在U中选取一个距离源点V0最小的顶点K,把K放入S中,这时候K在dist数组中的距离dist-k就是最短路径。

c.现在把K当成新的考虑点,重新建立dist数组,这一个判断条件是,如果从源点V0到这个顶点X的dist-X,比从源点V0到k然后在从k到X的dist-X要大,那么就把dist-X更新为dist-k+k到X的距离。(要知道只有这个条件出现才改变dist的值,如果有多条路径到假设点A,那么会在  “把K当成新的考虑点,重新建立dist数组“这句话把多条路径之间的比较问题给解决了,记住一点,在dist数组里存储的都是在----当前跟S中已有的顶点,到源点V0最短的路径 )把剩下的顶点都比较完了之后,回到b这个地方。同样的,把X当成了新的考虑点。

3)算法思考

为什么,Dijkstra算法不能计算有负权值的图?这个问题,我一直在想。现在我假设源点是A,A-->B是3,A-->C是2,B到C是-2,按照Dijkstra算法的思想步骤,C会是第一个被放到S集合中,并且dist等于2,但是能够很清楚的看出来,C的最短路径是1。这是一种情况,就只有负值边,另一种情况是,负值回路,在这个回路中,最短路径的值会越变越小。

还有一个问题,为什么要有负值的边?这个有什么意义?

我自己给了自己这样一个解释,那就是,你在旅游的过程中,不能老是花钱,还能够赚钱!!

 

 

const int MAX=32767;
const int N;//这个看数组的大小

int n;
int mp[N][N];//连接矩阵
int dist[N];//距离数组

void mindis(int vo)
{
int i,j;
bool S[N];//标记数组
for(i=1;i<=n;i++)
{
dist[i]=mp[vo][i];//初始化
S[i]=false;
}
dist[vo]=0;
S[vo]=true;

for(i=2;i<=n;i++)//b.c两个步骤
{
int mindist=MAX;
int u=vo;
for(j=1;j<=n;j++)
{
if((!S[j]) && dist[j]<mindist )
{
u=j;
mindist=dist[j];
}
}
S[u]=true;
for(j=1;j<=n;j++)
{
if( (!S[j]) && mp[u][j]<MAX )
{
if( dist[u]+mp[u][j]<dist[j] )
dist[j]=dist[u]+mp[u][j];
}
}
}
}

 

posted @ 2015-08-03 20:31  psurge  阅读(538)  评论(0)    收藏  举报