单源最短路径问题(dijkstra算法 及其 优化算法(优先队列实现))

时间:2023-03-09 00:26:54
单源最短路径问题(dijkstra算法 及其 优化算法(优先队列实现))
 #define _CRT_SECURE_NO_WARNINGS
/*
7 10
0 1 5
0 2 2
1 2 4
1 3 2
2 3 6
2 4 10
3 5 1
4 5 3
4 6 5
5 6 9
6
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std; const int maxn = + ;
const int INF = ;
int cost[maxn][maxn]; //表示边e=(u,v)的权值 (不存在这条边时设为INF)
int d[maxn]; //顶点出发的最短距离
bool used[maxn]; //已经使用过的图
int V, E;
void init();
void dijkstra(int s);
void input(); void init()
{
for (int i = ; i < V; i++) {
for (int j = ; j < V; j++) {
if (i == j) {
cost[i][j] = ;
}
else {
cost[i][j] = INF;
}
}
}
} void dijkstra(int s)
{
fill(d, d + V, INF);
fill(used, used + V, false);
d[s] = ; while (true) {
int v = -;
//从尚未使用过的顶点中选择一个距离最小的顶点
for (int u = ; u < V; u++) {
if (!used[u] && (v == - || d[u] < d[v])) {
v = u;
}
}
if (v == -) break; //已经没有尚未使用的点了
used[v] = true; //标志v已访问 for (int u = ; u < V; u++) {
d[u] = min(d[u], d[v] + cost[u][v]);
}
}
} void input()
{
int s, t, ct;
for (int i = ; i < E; i++)
{
cin >> s >> t >> ct;
cost[s][t] = cost[t][s] = ct;
}
} int main()
{
cin >> V >> E; //输入顶点数和边数
init(); //必须要初始化
input(); //输入临接的边和权值
dijkstra(); //设置起点
int ov;
cin >> ov; //输入终点
cout << d[ov] << endl;
return ;
}

//解法二:

需要优化的是数值的插入(更新)和取出最小值两个操作,因此使用堆就可以了。把每个顶点当前的最短距离用堆维护,在更新最短距离时,把对应的元素往根的方向移动以满足堆的性质。而每次从堆中取出的最小值就是下一次要使用的顶点。这样堆中元素共有O(|V|)个。更新和取出数值的操作有O(|E|)次,因此整个算法复杂度是O(|E|log|V|)。

下面是使用STL的priority_queue的实现。在每次更新时往堆里插入当前最短距离和顶点的值对。插入的次数是O(|E|)次,因此元素也是O(|E|)个。当取的最小值不是最短距离的话,就丢弃这个值。

 #define _CRT_SECURE_NO_WARNINGS
/*
7 10
0 1 5
0 2 2
1 2 4
1 3 2
2 3 6
2 4 10
3 5 1
4 5 3
4 6 5
5 6 9
6
*/
#include <iostream>
#include <vector>
#include <utility>
#include <queue>
#include <functional>
#include <algorithm>
#include <cstdio>
using namespace std; const int maxn = + ;
const int INF = ;
struct edge
{
int to, cost;
};
typedef pair<int, int> P; //first是最短距离,second是顶点的编号
int V, E;
vector<edge> G[maxn];
int d[maxn];
//void init();
void input(); void dijkstra(int s)
{
//通过指定greater<P>参数,堆按照first从小到大的顺序取出值
priority_queue<P, vector<P>, greater<P> > que;
fill(d, d + V, INF);
d[s] = ;
que.push(P(, s)); while (!que.empty()) {
P p = que.top(); que.pop();
int v = p.second;
if (d[v] < p.first) continue;
for (int i = ; i < G[v].size(); i++) {
edge e = G[v][i];
if (d[e.to] > d[v] + e.cost) {
d[e.to] = d[v] + e.cost;
que.push(P(d[e.to], e.to));
}
}
}
} //void init()
//{
//} void input()
{
int s, t, ct;
edge tmp;
for (int i = ; i < E; i++) {
cin >> s >> t >> ct;
tmp.to = t; tmp.cost = ct;
G[s].push_back(tmp);
//无向图,反向也需要连接
tmp.to = s; tmp.cost = ct;
G[t].push_back(tmp);
}
} int main()
{
cin >> V >> E;
//init();
input();
dijkstra();
int ov;
cin >> ov;
cout << d[ov] << endl;
return ;
}