图论基础笔记第二节

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等。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值