单源最短路径之dijkstra

Dijkstra算法使用的场合

1、单源:求一个源节点s到其他某些节点的最短路径

2、权重非负:节点之间的权重不能小于0

3、有向:结点之间的权重都是有向的

Dijkstra的描述

最短路径估计g(v):当前求得的s到v的最短距离(该路径不一定是最短路径)

最短路径d(v):s到v的最短路径距离

Dijkstra算法在运行的过程中维持的关键信息是一组点的集合S。从源节点s到该集合S中每个节点的最短路径已经找到。算法重复从节点集V-S中选择当前最短路径估计最小的节点u,将u加入到集合S,然后对所有从u出发的边进行松弛。

Dijkstra的java模板

	int n;//节点的个数
	int s;//源节点
	int d[]=new int[n];//d[v]:s到v的最短距离
	int vis[]=new int[n];//vis[v]=1:节点v属于集合S
	int g[]=new int[n];//g[v]:节点的v的最短估计路径
	int w[][]=new int[n][n];//w[i][j]:节点i到节点j的权重
	void dijkstra()
	{
		int MAX=0xffffff;
		int min=0;
		int tmp=0;
		Arrays.fill(g, MAX);
		Arrays.fill(w, -1);
对w赋值
		g[s]=0;
		for(int i=0;i<n;i++)
		{
			//*//找出V-S中最短估计路径距离最小的节点tmp
			min=MAX;
			for(int j=0;j<n;j++)
			{
				if(vis[j]==0 && g[j]<min)
				{
					tmp=j;
					min=g[j];
				}
			}
			//*//
			vis[tmp]=1;//将节点tmp加入到S中
			//**//对所有从tmp出发的节点进行松弛
			for(int j=0;j<n;j++)
			{
				if(vis[j]==0 && w[tmp][j]!=-1 && g[j]>g[tmp]+w[tmp][j])
				{
					g[j]=g[tmp]+w[tmp][j];
				}
			}
			//**//
		}
	}


证明Dijkstra的正确性

关键在于证明:对于每次选择加入到集合S中的节点u,都有g(u)=d(u)。

在证明之前先给出一条性质(摘自算法导论)

收敛性质:对于某些节点u,v,如果s~u~v是一条最短路径,并且在对边(u,v)进行松弛钱的任意时间有g[u]=d[u],则在之后的所有时间有g[v]=d[v]。

假设u是加入到S集合中的第一个不满足g[u]!=d[u]的节点,那么必然存在着一条从s到u的最短路径p,我们假设y是V-S上的一点,x是y的前驱节点,且x属于S(y可能是u,x可能是s)。

1、由于p是s到u的最短路径,所以p上路径s~y也是s到y的最短路径。

2、由于u是加入到S集合的第一个不满足g[u]=d[u]的节点,所以g[x]=d[x]。当x加入到S时,边(x,y)会被松弛

由1、2和收敛性质可知:g[y]=d[y]。

3、由于p是s到u最短路径,y是最短路径上位于u之前的节点,所以d[y]<=d[u]

根据以上两个个式子可推出:g[y]=d[y]<=d[u]<=g[u]

4、由于选着加入S时选择的是u,且u和y都在集合V-S中,所以又g[y]>=g[u]

所以,g[y]=d[y]=d[u]=g[u]。

这与假设矛盾。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值