Dijkstras算法

最短路径之Dijkstras算法

算法思路:

​ 算法核心操作是松弛操作

​ **松弛操作:**不记住这名字其实也是可以的,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZAM3tcC-1580967953420)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206112537920.png)]

现在有三条路径 {0,a},{0,b},{0,c},现在已知{0,a}这条路径最短,那么{0,a}则为0,a的最短路径,那么此时考虑从0到a再到到b,会不会比{0,b}这条路径更短呢? 如果更短,那么就找到了一条更短的路径。其核心思想为,从另一条已知的最短路径绕过去会不会比原来的路径长度更短。

来看整个算法流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQGIPhcb-1580967953422)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206125910972.png)]

目前整个图为初始状态,初始化一个数组用于保存从顶点0到其他顶点的距离

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3DKj442-1580967953425)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206130016914.png)]

现在从0顶点到任何顶点的距离都是无穷大,首先我们做一步初始操作,0到0的距离是为0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OtuEdZpA-1580967953426)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206130358096.png)]

黑色表示最短距离还未确定,红色表示最短距离已经确定,我们找出还未确定的最小的那个值为 0,0即为0到0的最短距离。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iaPsZjSY-1580967953426)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206130705469.png)]

确定了0到0的最短路径以后,接下来根据松弛操作,我们看经过0节点到其他节点的距离会不会更小呢。0的相邻节点有顶点1和顶点2通过计算我们发现0到1的距离为:{0,0}+{0,1} = 0+4 < ∞,所以将0到1的距离更新为4,0到2的距离为:{0,0}+{0,2} =0+2 < ∞,所以我们将0到2的距离更新为2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iEV1WBXi-1580967953427)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206131242850.png)]

接下来我们选取图中最小未确定的距离,遍历数组发现是2,那么从0到2的距离最小值即为2。因为从源点到其他顶点的距离最小的就是2,那么2必然就是从源点到该顶点的最短距离,如果2还不是源点到该顶点的最小距离,那么一定存在另外一条路劲,从源点出发,经过其他的顶点再到顶点2是最短的路径可以表示为{0,n} ->{n}->{n,2},但是从目前数组中可以得到的是{0,2}这条路径的值最小是2,由于不存在负权变,那么{0,n}+{0,n} > {0,n} > {0,2}的,所以可以认定{0,2}这条边是最短的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kz5ipMPr-1580967953429)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206131937405.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ra3WfBUz-1580967953430)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206133009279.png)]

确定了0到2的最短路径以后,接下来根据松弛操作,我们看经过2节点到其他节点的距离会不会更小呢。2的相邻节点有顶点1和顶点3和顶点4,通过计算我们发现0到2再到1的距离为:{0,0}+{0,2}+{2,1} = 0+2+1 < 4,所以将0到1的距离更新为3;0到2再到3的距离为:{0,0}+{0,2} + {2,3} =0+2+4 < ∞,所以我们将0到2的距离更新为6;0到2再到4的距离为:{0,0}+{0,2} + {2,4} =0+2+5< ∞,所以我们将0到2的距离更新为7;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Zov71bP-1580967953432)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206133148139.png)]

接下来我们选取图中最小未确定的距离,遍历数组发现是3,那么从0到3的距离最小值即为3。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwKlLNql-1580967953432)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206133256422.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UWespNSg-1580967953432)(C:\Users\zmh\AppData\Roaming\Typora\typora-user-images\image-20200206133313481.png)]

当节点1加入到确定确定最短距离顶点集合中后相应地开始更新,经过1能到达的邻居节点更短的距离,后面的历程我就不再继续演示了。

代码片段

void Dijkstras(G* g,int s){
	fill(dis,dis+g->v,INF);
	fill(visited, visited+g->v,false);	
	dis[s] = 0;//从s到s路径长度为0  
    pre[s] = s; //若要求从源节点到其他节点的具体路径,声明pre[]
	//这个地方不为visited[s] = true; 因为在下面要访问的所有顶点中第一个要访问的就是s 
	pii p(dis[s],s);//typedef pair<int,int> pii
	q.push(p);
	
	while(!q.empty()){
		/*
		int curdis = INF;//目前还未确定到源点的顶点的最小距离 
		int cur = -1;//其对应的下标
		//***这两句语句是写在循环里面的*** 
		 
		for(int i = 0; i<g->v; i++){
			if(!visited[i] && dis[i] < curdis){//!visited[i]表示到源点最小距离还未确定 
				curdis = dis[i];				//dis[i] < curdis 找到dis[]数组中值最小
				cur = i;						//且未确定的那个值和下标
			}
		}
		
		if(cur == -1) break;//若cur = -1,则visited中所有都是true,所有顶点都被确认了 
		*//*被注释的代码是未使用最小堆的代码*/ 
		 
		int cur = q.top().second;//取出未确定且距离最短的顶点的下标 
		q.pop();//弹出 
		if(visited[cur]) continue;//如果这个点已经被确定了,则不再进行此次循环,
									//由于某一个点的距离会被更新多次,所以已经确定了的顶点不用再继续了 
		visited[cur] = true;
		/*
		if(cur == d) { 如果只求s点到d点的路径,只需要添加上这段代码并添加上d参数 
			break;
		} 
		*/
		map<int,int>::iterator it = g->ag[cur].mp.begin();//遍历cur的边,计算经过cur后那些距离变得更短的边 
		for(;it != g->ag[cur].mp.end(); it++){
			if(!visited[it->first]){//首先这些顶点没有还未被确定 
				if(dis[cur] + it->second < dis[it->first]){//如果经过cur后到达该顶点的距离变小了
					dis[it->first] = dis[cur] + it->second;//,则更新这个距离 
					pii p1(dis[it->first],it->first);
					q.push(p1);
					pre[it->first] = cur;
				}
			}
		}
	}
}

dis[it->first],it->first);
q.push(p1);
pre[it->first] = cur;
}
}
}
}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值