最短路径问题
最短路径:
一张图中节点到节点之间所经过的边权和最小的路径,称为,之间的最短路径
具体包括下几种类型:
- 确定起点的最短路问题
- 确定终点的最短路问题
- 确定起点和终点的最短路问题
- 全局最短路问题
常见的解决算法有:
- 算法
- 算法
- 算法
算法:
单源最短路问题:
给出一张图的所有描述,求从某个给定的点出发到图中其他所有点的最短路径
算法描述:
我们规定集合为一个点集,[]代表从给定的起点出发到的最短路径长度,点集初始只有一个点,也就是给定的起点,从除去剩下的点集中找到节点满足[]最小,并且把加入到集合中,用来更新所有与直接相连的点的值,不断重复,直到集合中包含了所有图中的点。时间复杂度为(+)。
算法证明:
如果从到的最短路径经过了节点,那么这条路径上的之间的路径长度一定是路径之间的最短路径,因为如果存在另一条路径(,)是之间的最短路径,那么一定可以使用(,)来更新之间的路径从而得到一个更短的路径。这也就证明了为什么我们可以通过集合中的点来不断扩展更新,并且被更新的点可以被归入到集合中,我们保证了集合任意一个节点的值的最优性,那么通过更新的点的值也一定是最优的。
代码实现:
题意:
第一行给出两个整数m,n,接下来m行每行三个数a,b,c代表从a到b有一条长度为c的路径,问从n到1的最短路。
题解:
模板题
代码:
#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;
}
优化:
注意到每一次寻找节点满足[]最小都要遍历所有的点,我们可以使用一个数据结构来支持快速找到最小值并且将其删去,可以使用一个堆来维护所有的未进入集合的点,每一次从堆中找到最小值并且将其删去,就可以把时间复杂度降为()。