继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

最短路径问题-Dijkstra

Azura2001
关注TA
已关注
手记 4
粉丝 1
获赞 3

最短路径问题

最短路径:

一张图中节点uu到节点vv之间所经过的边权和最小的路径,称为uu,vv之间的最短路径

具体包括下几种类型:
  • 确定起点的最短路问题
  • 确定终点的最短路问题
  • 确定起点和终点的最短路问题
  • 全局最短路问题
常见的解决算法有:
  • FloydFloyd算法
  • DijkstraDijkstra算法
  • SPFASPFA算法

DijkstraDijkstra算法:

单源最短路问题:

给出一张图的所有描述,求从某个给定的点出发到图中其他所有点的最短路径

算法描述:

我们规定集合AA为一个点集,disdis[uu]代表从给定的起点出发到uu的最短路径长度,点集AA初始只有一个点ss,也就是给定的起点,从除去AA剩下的点集中找到节点uu满足disdis[uu]最小,并且把uu加入到集合AA中,用uu来更新所有与uu直接相连的点的disdis值,不断重复,直到AA集合中包含了所有图中的点。时间复杂度为OO(n2n^{2}+mm)。

算法证明:

如果从uuvv的最短路径经过了节点ijij,那么这条路径上的ijij之间的路径长度一定是路径ijij之间的最短路径,因为如果存在另一条路径rr(ii,jj)是ijij之间的最短路径,那么一定可以使用rr(ii,jj)来更新uvuv之间的路径从而得到一个更短的路径。这也就证明了为什么我们可以通过AA集合中的点来不断扩展更新,并且被更新的点可以被归入到AA集合中,我们保证了AA集合任意一个节点uudisdis值的最优性,那么通过uu更新的点vvdisdis值也一定是最优的。

代码实现:

POJ2387POJ2387

题意:

第一行给出两个整数m,n,接下来m行每行三个数a,b,c代表从a到b有一条长度为c的路径,问从n到1的最短路。

题解:

dijsktradijsktra模板题

代码:
#include<iostream>
#include<cstring>
#include<cmath>
const int mn=1000+10,me=2*mn+10;
int arcs[mn][mn];
int dis[mn];
bool vis[mn];
int m,n;
int cnt=1;
using namespace std;
void dijsktra(){
	for(int i=1;i<=n;i++)
			dis[i]=arcs[1][i];
	vis[1]=true;
	dis[1]=0;
	while(cnt<n){
		int minn=1;
		for(int i=1;i<=n;i++){
			if(dis[i]>dis[minn])
				minn=i;
		}
		for(int i=1;i<=n;i++){
			if(dis[i]<dis[minn]&&vis[i]==false)
				minn=i;
		}
		vis[minn]=true;
		for(int i=1;i<=n;i++)
			dis[i]=min(dis[i],dis[minn]+arcs[i][minn]);
		cnt++;
	}
}
int main(){
	cin>>m>>n;
	memset(arcs,0x3f,sizeof(arcs));
	memset(dis,0x3f,sizeof(dis));
	memset(vis,false,sizeof(vis));
	for(int i=1,x,y,z;i<=m;i++){
		cin>>x>>y>>z;
		arcs[x][y]=min(z,arcs[x][y]);
		arcs[y][x]=arcs[x][y];
	}
	dijsktra();
	cout<<dis[n]<<endl;
	return 0;
}

优化:

注意到每一次寻找节点uu满足disdis[uu]最小都要遍历所有的点,我们可以使用一个数据结构来支持快速找到最小值并且将其删去,可以使用一个堆来维护所有的未进入集合AA的点,每一次从堆中找到最小值并且将其删去,就可以把时间复杂度降为OO(mlognmlogn)。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP