Dijstra算法 + 堆优化
void Dijkstra(int s)
{
vector<int> dist; //该数组存储从源点s到w的最短距离, dist[s] = 0;
vector<int> path; //该数组储存从源点s到w的路径上经过的点, s-->w path[w] = s
vector<bool> collected; //该数组表示当前结点是否已经收录于最短路径集合中了
for (int i = 0; i < vertexNum; i++)
{
dist.push_back(65535);
path.push_back(-1);
collected.push_back(false);
}
dist[s] = 0;
for (auto w : Adj(s))
{
dist[w] = ptrGraph[s][w];
}
while (1)
{
int v = 65535;
for (int j = 0; j < vertexNum; j++)
{
if (!collected[j] && dist[j] < 65535)
{
v = j;
}
}
if (v == 65535)
{
break;
}
collected[v] = true;
for (auto w : Adj(v))
{
if (collected[w] == false)
{
if (dist[v] + ptrGraph[v][w] < dist[w])
{
dist[w] = dist[v] + ptrGraph[v][w];
path[w] = v;
}
}
}
}
}
该算法的时间复杂度,如果是直接扫描所有未收录的顶点,判断其dist的最小的顶点,则为 O(V^2 + E)。while循环为V次,每次扫描一遍顶点也需要V次,for循环对v的每个邻接点w的处理,总共相当于遍历了一遍图中的所有的边E。
若是将dist的值存于最小堆,则获取未收录顶点中dist值最小者为O(logV),在更新dist值的时候也需要O(logV)的时间复杂度。总的时间复杂度为O(VlogV + ElogV),当为稀疏图时,近似于O(VlogV)。如果对于E不是V^2的数量级,而是V的数量级,这种方式效果要好一些。
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <climits>
using namespace std;
struct Edge {
int to;
int length;
int price;
Edge(int b, int l, int p) : to(b), length(l), price(p) { }
};
struct Point {
int index; //该点的编号
int distance; //该点距离源点的距离
Point(int _id, int _dst) : index(_id), distance(_dst) { }
friend bool operator < (const Point& p1, const Point& p2) {
return p1.distance > p2.distance;
}
};
pair<int, int> Dijstra(vector<vector<Edge>>& Adj, int s, int t) {
int n = Adj.size();
vector<int> dist(n, INT32_MAX);
vector<int> cost(n);
vector<bool> collected(n, false);
priority_queue<Point> pq;
dist[s] = 0;
cost[s] = 0;
pq.push(Point(s, dist[s]));
while (!pq.empty()) {
int u = pq.top().index;
pq.pop();
if (collected[u]) continue;
collected[u] = true;
for (int i = 0; i < Adj[u].size(); i++) {
int v = Adj[u][i].to;
int len = Adj[u][i].length;
int p = Adj[u][i].price;
if (!collected[v]) {
if ((dist[v] > dist[u] + len) ||
(dist[v] == dist[u] + len && cost[v] > cost[u] + p)) {
dist[v] = dist[u] + len;
cost[v] = cost[u] + p;
pq.push(Point(v, dist[v]));
}
}
}
}
return pair<int, int>(dist[t], cost[t]);
}
int main()
{
int N, M;
while (cin >> N >> M) {
if (N == 0 && M == 0) break;
vector<vector<Edge>> Adj(N+1);
int a, b, l, p;
while (M--) {
cin >> a >> b >> l >> p;
Adj[a].push_back(Edge(b, l, p));
Adj[b].push_back(Edge(a, l, p));
}
int S, F;
cin >> S >> F;
pair<int, int> res = Dijstra(Adj, S, F);
cout << res.first << " " << res.second << endl;
}
return 0;
}