给出一个有向图G=(V, E),和一个源点v0∈V,请写一个程序输出v0和图G中其它顶点的最短路径。只要所有的有向环权值和都是正的,我们就允许图的边有负值。顶点的标号从1到n(n为图G的顶点数)。
时间: 2024-02-12 12:06:40 浏览: 110
有向图邻接表的建立,深度广度搜索及拓扑排序.zip_45V_bfs_dfs_有向图
5星 · 资源好评率100%
这个问题可以使用 Dijkstra 算法或者 Bellman-Ford 算法来解决。下面我分别介绍一下这两种算法的实现方法。
1. Dijkstra 算法
Dijkstra 算法是一种贪心算法,用于求解单源最短路径问题。其基本思想是:从源点开始,每次选择一个距离源点最近的未标记节点,将该节点标记并更新其邻居节点的距离。具体实现如下:
- 使用一个数组 dist 来保存每个节点到源点的最短路径长度,初始时将源点的 dist 值设为 0,其它节点的 dist 值设为无穷大。
- 使用一个优先队列来保存未标记节点,初始时将源点加入队列。
- 每次从队列中取出距离源点最近的未标记节点 u,将其标记为已访问,然后遍历 u 的所有邻居节点 v,如果从源点到 v 的路径经过 u 更短,则更新 v 的 dist 值,并将 v 加入队列中。
- 重复执行第三步,直到队列为空。
代码实现如下:
```c++
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Edge {
int v, w;
Edge(int _v, int _w) : v(_v), w(_w) {}
};
vector<Edge> adj[100010]; // 邻接表
bool vis[100010]; // 标记节点是否被访问过
int dist[100010]; // 记录每个节点到源点的最短距离
void dijkstra(int s) {
memset(vis, 0, sizeof(vis));
memset(dist, INF, sizeof(dist));
dist[s] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, s));
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i].v, w = adj[u][i].w;
if (!vis[v] && dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push(make_pair(dist[v], v));
}
}
}
}
int main() {
int n, m, s;
cin >> n >> m >> s;
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back(Edge(v, w));
}
dijkstra(s);
for (int i = 1; i <= n; i++) {
if (i == s) continue;
if (dist[i] == INF) cout << "INF" << endl;
else cout << dist[i] << endl;
}
return 0;
}
```
2. Bellman-Ford 算法
Bellman-Ford 算法是一种动态规划算法,用于求解单源最短路径问题。其基本思想是:从源点开始,依次对每条边进行松弛操作,重复执行 n-1 次,直到所有最短路径被计算出来。具体实现如下:
- 使用一个数组 dist 来保存每个节点到源点的最短路径长度,初始时将源点的 dist 值设为 0,其它节点的 dist 值设为无穷大。
- 重复执行 n-1 次以下操作:遍历所有边,对于每条边 (u, v, w),如果从源点到 v 的路径经过 u 更短,则更新 v 的 dist 值。
- 检查是否存在负环,如果存在负环,则无法计算出最短路径。
代码实现如下:
```c++
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Edge {
int u, v, w;
Edge(int _u, int _v, int _w) : u(_u), v(_v), w(_w) {}
};
vector<Edge> edges; // 存储所有边
int dist[100010]; // 记录每个节点到源点的最短距离
void bellman_ford(int s, int n, int m) {
memset(dist, INF, sizeof(dist));
dist[s] = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
int u = edges[j].u, v = edges[j].v, w = edges[j].w;
if (dist[u] != INF && dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
}
}
}
for (int i = 0; i < m; i++) {
int u = edges[i].u, v = edges[i].v, w = edges[i].w;
if (dist[u] != INF && dist[v] > dist[u] + w) {
cout << "Negative cycle detected" << endl;
return;
}
}
}
int main() {
int n, m, s;
cin >> n >> m >> s;
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
edges.push_back(Edge(u, v, w));
}
bellman_ford(s, n, m);
for (int i = 1; i <= n; i++) {
if (i == s) continue;
if (dist[i] == INF) cout << "INF" << endl;
else cout << dist[i] << endl;
}
return 0;
}
```
以上两种算法均能够解决单源最短路径问题,选择哪一种算法取决于具体的情况。如果图比较稠密,使用 Dijkstra 算法效率更高;如果图比较稀疏,使用 Bellman-Ford 算法更合适。
阅读全文