【算法导论】单源最短路径之Dijkstra算法

Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄。

迪杰斯特拉提出的按路径长度递增次序来产生源点到各顶点的最短路径的算法思想是:对有n个顶点的有向连通网络G=(V, E),首先从V中取出源点u0放入最短路径顶点集合U中,这时的最短路径网络S=({u0}, {}); 然后从uU和vV-U中找一条代价最小的边(u*, v*)加入到S中去,此时S=({u0, v*}, {(u0, v*)})。每往U中增加一个顶点,则要对V-U中的各顶点的权值进行一次修正。若加进v*作为中间顶点,使得从u0到其他属于V-U的顶点vi的路径不加v*时最短,则修改u0到vi的权值,即以(u0,
v*)的权值加上(v*, vi )的权值来代替原(u0, vi )的权值,否则不修改u0到vi的权值。接着再从权值修正后的V-U中选择最短的边加入S中,如此反复,直到U=V为止。

上面的说明都很抽象,下面图解算法思想:

原始图为:

【算法导论】单源最短路径之Dijkstra算法

寻找最短路径的过程如下:

【算法导论】单源最短路径之Dijkstra算法

对第一个图中的有向网络按以上算法思想处理,所求得的从源点F到其余顶点的最短路径的过程如图13.16所示。其中单圆圈表示U中的顶点,而双圆圈表示V-U中的顶点。连接U中两个顶点的有向边用实线表示,连接U和V-U中两个顶点的有向边用虚线表示。圆圈旁的数字为源点到该顶点当前的距离值。

        初始时,S中只有一个源点F,它到V-U中各顶点的路径如图13.16(a)所示;选择图13.16(a)中最小代价边(F, B),同时由于路径(F, A)大于(F, B, A)和(F, C)大于(F, B, C),进行相应调整可得到图13.16(b);选择图13.16(b)中的最小代价边(B, C),同时由于(F, B, A)大于(F, B, C, A),进行相应调整可得到图13.16(c);选择图13.16(c)中最小代价边(C, A)即可得到图13.16(d);选择图13.16(d)中最小代价边(F,
D) 即可得到图13.16(e); 最后选择(F, E)即可得到图13.16( f )。

具体的程序实现如下:

#include<stdio.h>
#define M 12//边数
#define N 6//顶点数
#define MAX 10000

void Dijkstra(int v, int dist[][N],int D[N],int p[N],int s[N]) ;
int flag[N]={0};
int flag1=0;
int flag2=0;
typedef struct
{
	int startvex;
	int endvex;
	int length;
}edge;//边的结构体
edge T[M];
void main()
{
	int dist[N][N]={{0,6,MAX,8,MAX,MAX},//图的邻接矩阵
					{18,0,7,MAX,MAX,10},
					{9,MAX,0,15,MAX,MAX},
					{MAX,MAX,12,0,MAX,MAX},
					{MAX,MAX,4,MAX,0,MAX},
					{24,5,MAX,25,MAX,0}};
	int D[N]={0};
	int p[N]={0};
	int s[N]={0};
	int num=0;
    Dijkstra(5,dist,D, p,s) ;
}

 void Dijkstra(int v, int dist[][N],int D[N],int p[N],int s[N])
 { 	int i, j, k, v1, min, max=10000, pre; 	/* Max中的值用以表示dist矩阵中的值 */
	v1=v;
	for( i=0; i<N; i++)              /* 各数组进行初始化 */
	{	D[i]=dist[v1][i];
		if( D[i] != MAX )  p[i]= v1+1;
		else p[i]=0;
		s[i]=0;
	}

	s[v1]=1;     		             /* 将源点送U */
	  for( i=0; i<N-1; i++) 	 /* 求源点到其余顶点的最短距离 */
	{	min=10001;    /* min>max, 以保证值为的顶点也能加入U */
		for( j=0; j<N-1; j++)
			  if ( ( !s[j] )&&(D[j]<min) )  		/* 找出到源点具有最短距离的边 */
		  		{min=D[j];
						k=j;
		 			}
				s[k]=1;  /* 将找到的顶点k送入U */
	for(j=0; j<N; j++)
	 if ( (!s[j])&&(D[j]>D[k]+dist[k][j]) ) /* 调整V-U中各顶点的距离值 */
		{D[j]=D[k]+dist[k][j];
		p[j]=k+1;                  	/* k是j的前趋 */
				}
			}                           	/*  所有顶点已扩充到U中 */
			for( i=0; i<N; i++)
			{
				printf(" %d : %d ", D[i], i);
				pre=p[i];
			while ((pre!=0)&&(pre!=v+1))
			{	printf ("<- %d ", pre-1);
				pre=p[pre-1];
			}
			printf("<-%d \n", v);
		}
}

结果显示如下:

【算法导论】单源最短路径之Dijkstra算法

注:如果程序出错,可能是使用的开发平台版本不同,请点击如下链接: 解释说明

原文:http://blog.csdn.net/tengweitw/article/details/17510891

作者:nineheadedbird

上一篇:C# 多线程详解


下一篇:微信小程序:添加全局的正在加载中图标效果