1. Dijkstra算法求最短路
// Dijkstra算法是最短路径算法的一种。它的基本思想是以起始点为中心向外层次扩展,广度优先;并且每次扩展走到起点到该点的最短路径。以下是一种简化的C++实现:
#include <iostream>
#include <vector>
#include <queue>
#include <limits>
using namespace std;
const int INF = numeric_limits<int>::max();
// 邻接表,表示图的信息
vector<vector<pair<int, int>>> adj;
vector<int> dijkstra(int start, int n) {
// 初始化距离数组为无穷大
vector<int> dist(n, INF);
// 设置起点到起点的距离为0
dist[start] = 0;
// 标记数组,表示该点是否已经遍历过
vector<bool> visited(n, false);
// 循环n次,因为最多处理图中所有的节点
for (int i = 0; i < n; ++i) {
int u = -1;
// 寻找未选中的最小距离的顶点
for (int j = 0; j < n; ++j) {
if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
u = j;
}
}
// 标记该顶点为已选中
visited[u] = true;
// 遍历顶点u的所有相邻顶点
for (const auto &[v, w] : adj[u]) {
if (!visited[v] && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
return dist;
}
int main() {
int n, m;
cin >> n >> m; // 输入节点数和边数
adj.resize(n); // 初始化邻接表
for (int i = 0; i < m; ++i) {
int u, v, w;
cin >> u >> v >> w; // 输入边和权值
adj[u].emplace_back(v, w); // 注意这里是有向图
}
int start;
cin >> start; // 输入起点
// 使用dijkstra算法计算从起点到其他点的最短路径
vector<int> dist = dijkstra(start, n);
// 输出获取的距离
for (int i = 0; i < n; ++i) {
cout << "距离 " << start << " 到 " << i << " 的最短路径为: " << dist[i] << endl;
}
return 0;
}
输入: (由于是有向图,所以每条边要输入两次)
节点 0-5 共六个节点,18条边,示例用的是离散数学ppt所给实例图
6 18
0 1 3
1 0 3
1 3 1
3 1 1
0 3 5
3 0 5
1 2 6
2 1 6
3 2 3
2 3 3
3 4 1
4 3 1
4 5 6
5 4 6
2 4 2
4 2 2
2 5 3
5 2 3
0
输出:(每个节点下标从0开始)
距离 0 到 0 的最短路径为: 0
距离 0 到 1 的最短路径为: 3
距离 0 到 2 的最短路径为: 7
距离 0 到 3 的最短路径为: 4
距离 0 到 4 的最短路径为: 5
距离 0 到 5 的最短路径为: 10
这个示例使用邻接表表示图,对图中每个顶点进行循环处理,找到未选中距离最小的顶点,然后更新这个顶点的所有邻接顶点的距离。这个实现的时间复杂度是O(n^2),适合在入门学习阶段。后续可以学习优化的实现,如使用优先队列来加速Dijkstra算法。
重点:
// 循环n次,因为最多处理图中所有的节点
for (int i = 0; i < n; ++i) {
int u = -1;
// 寻找未选中的最小距离的顶点
for (int j = 0; j < n; ++j) {
if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
u = j;
}
}
// 标记该顶点为已选中
visited[u] = true;
// 遍历顶点u的所有相邻顶点
for (const auto &[v, w] : adj[u]) {
if (!visited[v] && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
这部分代码是实现Dijkstra算法的核心部分。我将详细解释这部分代码的每个部分。
1.
for (int i = 0; i < n; ++i) { ... }
这是一个循环,它将遍历每个顶点,并且,我们将更新与这些顶点相邻的其它顶点的最短距离。因此,这个循环将执行n次,n是顶点的数量。
2.
int u = -1;
我们将要在这次迭代中选中的顶点的编号。初始值为-1,表明尚未选中任何顶点。
3. 寻找未选中的最小距离的顶点
这个嵌套循环用于找到未访问顶点中,距离最小的顶点。这被称为贪心选择。
for (int j = 0; j < n; ++j) {
if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
u = j;
}
}
4. `visited[u] = true;`
将找到的距离最小的顶点标记为已选中。我们不再考虑已经选中的顶点。
5. 遍历选中顶点u的所有相邻顶点
接下来,我们将遍历选中的顶点u的所有相邻顶点(顶点v和边的权值w)。我们将检查如果通过顶点u到达顶点v的距离小于当前已知的距离,那么就更新顶点v的距离。
for (const auto &[v, w] : adj[u]) {
if (!visited[v] && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
那么通过迭代n次,我们可以保证每个顶点都会被遍历并更新相邻顶点的距离。在循环结束后,`dist`数组将包含从起点到每个顶点的最短距离。
2. 两个矩阵相乘的乘法
// 要在C++中实现矩阵相乘,可以使用嵌套循环遍历矩阵的行和列,并将乘积累加到结果矩阵中。以下是一个简单的示例代码,展示了如何用C++实现两个矩阵相乘:
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> matrix_multiply(const vector<vector<int>> &A, const vector<vector<int>> &B) {
int a_rows = A.size();
int a_cols = A[0].size();
int b_rows = B.size();
int b_cols = B[0].size();
if (a_cols != b_rows) {
cout << "矩阵无法相乘,A的列数与B的行数不相等" << endl;
return {{}};
}
vector<vector<int>> result(a_rows, vector<int>(b_cols, 0));
for (int i = 0; i < a_rows; ++i) {
for (int j = 0; j < b_cols; ++j) {
for (int k = 0; k < a_cols; ++k) {
result[i][j] += A[i][k] * B[k][j];
}
}
}
return result;
}
int main() {
vector<vector<int>> A = {
{1, 2, 3},
{4, 5, 6}
};
vector<vector<int>> B = {
{7, 8},
{9, 10},
{11, 12}
};
vector<vector<int>> C = matrix_multiply(A, B);//计算乘积后的矩阵
for (const auto &row : C) {
for (int value : row) {
cout << value << " ";
}
cout << endl;
}
return 0;
}
// 这段示例代码将两个矩阵A和B相乘,并将结果打印到控制台。当然,这里的实现方式较为简单,可能不适用于很大的矩阵或特殊的数据结构,但它是一个很好的入门示例。要提高效率,可以考虑使用更高级的线性代数库如Eigen和Armadillo等。