dijkstra可用于求单个顶点到其他顶点的最短路径
其核心思想是DP,用已经求出的最短路径去更新到其他点的最短路径
时间复杂度优秀但不适用于带负权边的图。
具体做法:用dis存储起始点到各个点的当前距离,初始化为inf,到自己的距离初始化为0
每次取出距起点距离最近的点,用这个点去更新起点到其他点的距离,然后标记避免重复进行操作
朴素做法是O(n^2)的,但我们可以利用每次都取出的是最小距离这个特性利用优先队列对其进行优化
代码:
const int maxn = 1e4 + 5; int n,m,s; struct edge{ int to,w; }; struct node{ int w,now; bool operator<(const node a) const { return w > a.w; } }; int a,b,c; vector<edge> mp[maxn]; //vector存边 int dis[maxn]; priority_queue<node> q; //优先队列对每个顶点进行处理 int f[maxn]; //标记当前顶点是否已经对其他点进行过更新操作 int main(){ cin>>n>>m>>s; while(m--){ scanf("%d%d%d", &a, &b, &c); mp[a].push_back(edge{b,c}); } //读入边 for(int i = 1; i <= n; i++) dis[i] = 0x3f3f3f3f; dis[s] = 0; //初始化dis数组 q.push(node{0,s}); while(!q.empty()){ node x = q.top(); q.pop(); int u = x.now; if(f[u]) continue; f[u] = 1; for(int i = 0; i < mp[u].size(); i++){ if(dis[mp[u][i].to] > dis[u] + mp[u][i].w){ dis[mp[u][i].to] = dis[u] + mp[u][i].w; q.push(node{dis[mp[u][i].to], mp[u][i].to}); } } //dijkstra核心代码 } //优先队列处理 for(int i = 1; i <= n; i++) cout<<dis[i]<<" "; return 0; }
dijkstra的核心就是
if(dis[mp[u][i].to] > dis[u] + mp[u][i].w){
dis[mp[u][i].to] = dis[u] + mp[u][i].w;
如果可以将距离缩短,更新距离并将该点入队(因为已经是距起点最近的点了,更新出的距离也会是最短距离,其他点不可能将它更新到更短的距离)
因此每次更新后入队的点都已经是距源点的最近距离了,因此每个点只需要入队一次。
从而有了O(mlogn)的复杂度