DIJKSTRA算法实现单源最短路


本人很懒并且很渣,所以写得不合适的地方还请各位大牛指出,


2014年04月16日_最短路

注:下面针对的图是无向图,并且采用邻接矩阵的方式存储图


   先来说明下什么是最短路,从一个给定的顶点开始,到任意一个顶点的最短路径,就成为源点到该点的最短路径


 算法原理:


 按路径长度递增次序产生最短路径算法:


  把V分成两组:


  (1)S:已求出最短路径的顶点的集合


  (2)V-S=T:尚未确定最短路径的顶点集合


  将T中顶点按最短路径递增的次序加入到S中.


  保证:

    (1)从源点V0到S中各顶点的最短路径长度都不大于从V0到T中任何顶点的最短路径长度


  (2)每个顶点对应一个距离值


  S中顶点:从V0到此顶点的最短路径长度


  T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度


  依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和 。

好的,这不是我的风格,本段话摘自勇者王的博客。。。

   接下来是我自己的理解:其实这个算法就是把图中所有的顶点分成两个几个s,v,起先s集合只有给定的源点,然后去寻找当前的最短路,把另个属于v集合的顶点加入到s集合,重复上述操作,知道s里包含所有的顶点、

   来看一个例子  ,下图是一个普通的带权值的有向图,我们把顶点1作为源点,接下来去寻找最短路,先给出我的一张手绘稿

2014年04月16日_sed_02

       


  

  先把上面的三张图理解了

下面是代码实现


  先说下使用的一些数据结构

int G[][],  矩阵,存放权值


int prev[],这个一维数组用来存放最短路上一个顶点的前一个顶点


int dist[],这个一维数组存放从源点出发到任意点的最短路


bool used[],标记数组,其实就是来判断顶点是否加入到集合s中


好的,有了这些基础,差不多可以码代码了,不过我们得定义一些宏


#define maxn 105 //最大顶点个数


#define mx 10000000   //表示两个点之间没有路径


PS:这个代码是我AC的一道杭电acm上的题的源码,比较水的,我加了下注释 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1874

#include<stdio.h>

#define maxn 105

#define mx 10000000

int G[maxn][maxn];

int prev[maxn],dist[maxn];

void Dijkstra(int n,int Source_v)

{

     bool used[maxn]; //作用上面已经介绍过

     int i ,j,k;

     for(i=1;i<=n;i++)

    {

       used[i]=0; //初始化

       dist[i]=G[Source_v][i];//那么一开始的最短路当然是直接由源顶点到目标顶点的权值的大小

		if(dist[i]==mx)//如果说没有直接路径

			prev[i]=0; //我们认为这个顶点的依附顶点(前一个顶点)为0

		else

		    prev[i]=Source_v;//与源顶点直接相连 ,前一个顶点就是源顶点

	} 



	used[Source_v]=1; //表示源顶点已经标记,已加入到集合s中

	dist[Source_v]=0;//源顶点到源顶点距离为0 

	for(i=2;i<=n;i++)//寻找最短路 ,注意i是从2开始循环的,第一个顶点是源顶点

	{

		int u=Source_v;//存放一个存在当前最小权值边的顶点 

		int min=mx;

		for(j=1;j<=n;j++)  //此循环的目的是寻找到当前最小权值边

			if(!used[j] && min>dist[j]) //满足条件:既没有加入到集合s中,也比当前最小值要更小

			{

				min=dist[j];  //更新

				u=j;

			}

		used[u]=1;//显然要把这个顶点加进来,标记1

		for(j=1;j<=n;j++) //更新

		{

			if(!used[j] && G[u][j] < mx)//加入从u到j有路径

			{

				int newdist=G[u][j]+dist[u];//松弛操作

				if(newdist<dist[j])//判断Soure_v到j的路径和Source_v到u再到j的路径大小

				{

					dist[j]=newdist;

					prev[j]=u;

				}

			}

		}

	} 

}

int main()

{

	int n,m;

	while(~scanf("%d%d",&n,&m))

	{

		int i,j,a,b,c,s,t;

		for(i=0;i<=n;i++)

		  for(j=0;j<=n;j++)

		    {

                       	G[i][j]=mx;

                       G[j][i]=mx;//这样表示无向图

    }

		for(i=1;i<=m;i++)

		{

			scanf("%d%d%d",&a,&b,&c);

			if(c<G[a+1][b+1]) //防止重边

			{

				G[a+1][b+1]=c;

		    	G[b+1][a+1]=c;

			}

			

		}

		scanf("%d%d",&s,&t);

		s+=1;

		t+=1;

		Dijkstra(n,s);

		if(dist[t]!=mx)

		     printf("%d\n",dist[t]);

                else

                    printf("-1\n");

	}

	return 0;

}