注意:Dijkstra算法只适用于边权为非负值的带权图
时间复杂度为O(m*log n)级别
主要思路:(采用STL中的优先队列进行优化)
准备工作:先用vector容器开适当大小的数组存放与每个点相连点的位置与边权(用pair类型成对存放),创建dis[N]来存放所有点到起始点的距离,并将所有点到起始点的距离初始化为INF(int范围内最大的数),以便后续更新最短距离。创建vis[N]来标记某个点是否被更新过。
将某点的编号和该点当前到起始点最短距离存入队列(假设点1为起始点,点1到1的最短距离为0,那么将存入(1,0)),当队列不为空时选出堆顶元素(以下操作一直循环到队列为空),用该点(假设为点u)的位置带入vector容器遍历与点u相连的点(假设为点v),如果dis[v]>dis[u]+边u-v的边权(用w表示),就将dis[v]更新为dis[u]+w;最后再把(v,dis[v])存入队列即可。
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
const int INF=1e9;
int dis[N];
bool vis[N];
vector <pair<int,int> >g[N];
struct note{
int id;//点的位置
int d;//该点到起始点的最短距离
};
bool operator<(note a,note b){//重载小于号运算符,让堆元素从小到大排列
return a.d>b.d;
}
priority_queue<note> que;
int n,m,u,v,w;
Dijkstra(int st){
for(int i=1;i<=n;i++){
vis[i]=0,dis[i]=INF;//初始化
}
dis[st]=0;
que.push({st,0});
while(!que.empty()){
note t=que.top();que.pop();//每次取出堆顶元素后弹出该元素
int u=t.id;
if(vis[u]) continue;//如果已经被更新过就跳过该点
vis[u]=1;
for(auto eg:g[u]){//遍历与点u相邻的所有点
int v=eg.first;
int w=eg.second;
if(dis[v]>dis[u]+w) dis[v]=dis[u]+w;
que.push({v,dis[v]});
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
g[u].push_back({v,w});
}
int st;cin>>st;
Dijkstra(st);
for(int i=1;i<=n;i++){
cout<<st<<"->"<<i<<" shortest path is"<<dis[i]<<endl;
}
return 0;
}