📅  最后修改于: 2023-12-03 14:58:27.897000             🧑  作者: Mango
本题为GATE(印度研究生入学考试)的计算机科学题目,属于2007年的试题。
给定一个有向图 $G(V, E)$,其中 $V$ 是节点集,$E$ 是有向边集。每条边 $e=(u, v)$ 都有一个非负权重 $w(e)$。假设所有的边都是有向的,也就是说,如果存在一条边 $(u,v)$,则不存在一条边 $(v,u)$。
你需要编写一个程序,计算出从源节点 $s$ 到每个其他节点的最短路径。你的程序应该输出一个数组 $dist[0..|V|-1]$,其中 $dist[i]$ 是从源节点 $s$ 到节点 $i$ 的最短距离。如果从源节点 $s$ 不能到达节点 $i$,则 $dist[i]$ 应为 $\infty$。请注意,你需要使用 Dijkstra 算法来解决此问题。
Dijkstra 算法是求解单源最短路径问题的经典算法,可以在有向边的权重非负时使用。本题要求实现 Dijkstra 算法,计算从源节点到所有其他节点的最短路径。
Dijkstra 算法从源节点开始,每次选择距离最短的节点,并更新该节点的邻居节点的距离。该过程一直重复,直到所有节点都被访问或者不存在通往目标节点的路径为止。
具体实现时,我们可以使用优先队列来存储待处理的节点,并按距离从小到大排序。每次从队列中取出距离最小的点 $u$,然后遍历 $u$ 的所有邻居 $v$,如果从 $s$ 到 $v$ 的距离可以通过 $u$ 更新,则更新距离并将 $v$ 加入到队列中。
本题的算法实现相对较为简单,关键在于数据结构的选择。我们可以使用 C++ STL 中的 priority_queue 来实现优先队列,该容器可以自动维护元素的顺序。
具体实现时,我们可以使用一个长度为 $|V|$ 的数组 $dist$ 来记录每个节点到源节点的最短距离,初始化时将所有节点的距离都设为 $\infty$。然后将源节点加入到优先队列中,同时将该节点的距离设为 $0$,表示到自身的距离为 $0$。接下来,每次从队列中取出距离最小的节点 $u$,遍历其所有邻居节点 $v$,如果从 $s$ 到 $v$ 的距离可以更新,则更新距离并将 $v$ 加入到队列中。最终,数组 $dist$ 中存储的就是源节点到每个节点的最短距离。
下面是 C++ 的代码实现示例(仅供参考):
#include <iostream>
#include <vector>
#include <queue>
#include <functional>
using namespace std;
const int INF = 1e9;
int main() {
int n, m, s;
cin >> n >> m >> s;
vector<vector<pair<int, int>>> adj(n);
for (int i = 0; i < m; ++i) {
int u, v, w;
cin >> u >> v >> w;
adj[u].emplace_back(v, w);
}
vector<int> dist(n, INF);
dist[s] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.emplace(0, s);
while (!pq.empty()) {
int u = pq.top().second;
int u_dist = pq.top().first;
pq.pop();
if (u_dist != dist[u]) continue;
for (auto [v, w] : adj[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.emplace(dist[v], v);
}
}
}
for (int d : dist) {
if (d == INF) cout << "INF\n";
else cout << d << '\n';
}
}
以上代码使用 $vector$ 来存储邻接表,使用 $priority_queue$ 来维护优先队列。需要注意的是,$priority_queue$ 中的元素是一对 $(dist[u], u)$,其中 $u$ 是节点编号,$dist[u]$ 是从源节点到 $u$ 的距离,因此我们需要把元素的第一项设为距离 $dist[v]$。此外,为了避免重复加入节点,我们需要在加入节点前检查该节点的距离是否已经被更新。