dijkstra是求单元最短路的基本算法,大体思路为:
- 循环n次
- 每次找出离起点最近的点,(如果这个点已经讨论过,跳过下一个),讨论它能到达的所有下一个点v,如果起点到v的距离大于起点到u的距离加上边的权值,则更新起点到v的距离,称为松弛操作
- 因为一个点讨论过就不会再讨论,所以总共循环n次
//dijkstra
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10000 + 10;
const int INF = 0x3f3f3f3f;
int vis[MAXN], d[MAXN];
int n, m;
struct edge
{
int to, next, w;
}e[MAXN];
int cnt, head[MAXN];
void add(int u, int v, int w)
{
e[++cnt].next = head[u];
head[u] = cnt;
e[cnt].to = v;
e[cnt].w = w;
}
int main()
{
freopen("sp.in", "r", stdin);
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c); add(b, a, c);
}
for(int i = 2; i <= n; i++) d[i] = INF;
d[1] = 0;
for(int i = 1; i <= n; i++) //每有一个点被取出进行松弛后就必再松弛,所以总共循环n
{
int minn = INF;
int u;
for(int i = 1; i <= n; i++) if(!vis[i] && d[i] < minn) minn = d[i], u = i;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next)
if(d[e[i].to] > d[u] + e[i].w) d[e[i].to] = d[u] + e[i].w;
}
return 0;
}
因为找距离最小的点和找所有中点都要遍历,所以复杂度较高(当然,这已经比用邻接矩阵存储好的多了),所以在找距离最小的点时可以用到优先队列,每次只取取出队首元素就行了,但是这取出的只是队首元素的值,我需要用到它的下标,所以我们可以将它的值和它的下标打包
typedef pair<int, int> pii;
然后再放到优先队列中去
priority_queue<pii, vector<pii>, greater<pii> >;
因为优先队列需要按权值比较,所以应该把权值放在第一位
q.push(make_pair(d[i], i));
其他的部分和优化前区别不大,下面是代码
//dijkstra 优先队列优化
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10000 + 10;
const int INF = 0x3f3f3f3f;
int vis[MAXN], d[MAXN];
int n, m;
struct edge
{
int to, next, w;
}e[MAXN];
int cnt, head[MAXN];
void add(int u, int v, int w)
{
e[++cnt].next = head[u];
head[u] = cnt;
e[cnt].to = v;
e[cnt].w = w;
}
typedef pair<int, int> pii; //因为不仅要去出优先队列中最小的元素,还要知道它对应的点的下标,所以将它和下标打包
priority_queue<pii, vector<pii>, greater<pii> > q;
int main()
{
freopen("sp.in", "r", stdin);
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c); add(b, a, c);
}
for(int i = 2; i <= n; i++) d[i] = INF;
q.push(make_pair(d[1], 1));
while(!q.empty())
{
pii t = q.top(); q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next) if(d[e[i].to] > d[u] + e[i].w)
{
d[e[i].to] = d[u] + e[i].w;
q.push(make_pair(d[e[i].to], e[i].to));
}
}
for(int i = 1; i <= n; i++)
cout << d[i] << " ";
return 0;
}