首页 > 其他 > 详细

单源堆优化Dijkstra

时间:2019-06-21 18:52:23      阅读:104      评论:0      收藏:0      [点我收藏+]

**基本**和单源最短路是重题

因为题目中说了Dijkstra,干啥还用~~死了的SPFA?~~

估计用Floyd100%会挂...

那么就用堆优化的Dijkstra~~(迪杰克斯歘)~~

关于什么是Dijkstra?

左转百度

但是我自己都觉得那个讲的太复杂,就简单的讲一下吧

Dijkstra不会死去的条件:

该有权图不含负权边时间复杂度为O(n^2)

介绍一下:

Dijkstra类似于贪心

首先先确定一个源点(这里就是1号点),先把所有Dis(1,i)(i!=1)都定为INF,然后先遍历一遍,把与点1相连的点(即只用走一个连边)的点i的距离都第一次直接处理为Dis(1,i)

第二次遍历把与`Dis(1,i)<INF`的点有连接的点j的Dis处理为Dis(1,i,j)意为用i点的Dis来给j点附上Dis,可以说`Dis(1,j)=Dis(1,i)+Dis(i,j);`

之后我们重复第二次的操作,不过这次会多一种情况,即用Dis(j)来处理Dis(i),就是说这次遍历到j点的时候,如果有`Dis(1,j,i)<Dis(1,i)<INF`,我们就Dis(1,i)的值变为 `min(Dis(1,j),Dis(1,j)+Dis(j,i))`

遍历过后,如果仍有Dis(k)=INF的话,就证明点1无法到点k,所以我们只需要输出`-1`就可以了

那么什么是堆优化Dijkstra呢?

每次扩展一个距离最小的点,再更新与其相邻的点的距离。
如何寻找距离最小的点?
优化方案是建一个小根堆,小根堆里存储由当前结点更新距离的所有点,那么堆顶就是距离最小的点

建一个小根堆,用来存储结点的序号,用一个数组来存储第i个结点在堆中的位置,用一个标记数组来记录结点是否在堆中

对于小根堆的操作还是基本的put() 和get() ,但由于有的结点已经在堆中了,所以可以把put() 拆为插入堆和调整位置两个部分

```
1.将与源点相邻的点进行松弛操作后加入堆
2.取出位于堆顶的结点
3.若取出的点为终点,则结束算法
4.将与当前结点相邻的点进行松弛操作
(1)如果该点已经在堆中,就调整在堆中的位置
(2)如果该点不在堆中,就加入堆
```

代码如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;

typedef long long ll;
const int MAXN = 1e5 + 10;
const ll INF = 1ll<<62;
vector<int>e[MAXN];
vector<int>w[MAXN];
bool vis[MAXN];
ll d[MAXN];
int pre[MAXN];
int n;

struct Node {
ll d;
int u;
bool operator < (const Node & rhs) const {
return d > rhs.d;
}
};

void Dijkstra() {
priority_queue<Node>q;
for( int i=1; i<=n; i++ ) d[i] = INF;
d[1] = 0;
memset(vis, 0, sizeof(vis));
Node tn;
tn.d = 0, tn.u = 1;
q.push(tn);
while(!q.empty()) {
Node t = q.top();
q.pop();
int u = t.u;
if(vis[u]) continue;
vis[u] = true;
for( int i=0; i<e[u].size(); i++ ) {
int v = e[u][i];
if(d[v] > d[u] + w[u][i]) {
d[v] = d[u] + w[u][i];
pre[v] = u;
tn.d = d[v], tn.u = v;
q.push(tn);
}
}
}
}

int main() {
int m;
while(scanf("%d%d", &n, &m) != EOF) {
for( int i=1; i<=n; i++ ) e[i].clear(), w[i].clear();
int a, b, c;
for( int i=0; i<m; i++ ) {
scanf("%d%d%d", &a, &b, &c);
e[a].push_back(b);
w[a].push_back(c);
e[b].push_back(a);
w[b].push_back(c);
}
Dijkstra();
if(d[n] == INF) printf("-1\n");
else {
e[1].clear();
e[1].push_back(n);
while(pre[n] != 1) {
n = pre[n];
e[1].push_back(n);
}
e[1].push_back(1);
for( int i=e[1].size()-1; i>0; i-- ) printf("%d ", e[1][i]);
printf("%d\n", e[1][0]);
}
}
return 0;
}

 

单源堆优化Dijkstra

原文:https://www.cnblogs.com/j1yx/p/11066192.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!