卡码网KamaCoder 94. 城市间货物运输 I

题目来源:94. 城市间货物运输 I

C++题解1(来源代码随想录):Bellman_ford 

本题是经典的带负权值的单源最短路问题,此时就轮到Bellman_ford登场了。Bellman_ford算法的核心思想是 对所有边进行松弛n-1次操作(n为节点数量),从而求得目标最短路

对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离,这里 说的是 一条边相连的节点。

需要对所有边松弛几次才能得到 起点(节点1) 到终点(节点6)的最短距离呢

节点数量为n,那么起点到终点,最多是 n-1 条边相连。

#include <iostream>
#include <vector>
#include <list>
#include <climits>
using namespace std;

int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;

    vector<vector<int>> grid;

    // 将所有边保存起来
    for(int i = 0; i < m; i++){
        cin >> p1 >> p2 >> val;
        // p1 指向 p2,权值为 val
        grid.push_back({p1, p2, val});

    }
    int start = 1;  // 起点
    int end = n;    // 终点

    vector<int> minDist(n + 1 , INT_MAX);
    minDist[start] = 0;
    for (int i = 1; i < n; i++) { // 对所有边 松弛 n-1 次
        for (vector<int> &side : grid) { // 每一次松弛,都是对所有边进行松弛
            int from = side[0]; // 边的出发点
            int to = side[1]; // 边的到达点
            int price = side[2]; // 边的权值
            // 松弛操作 
            // minDist[from] != INT_MAX 防止从未计算过的节点出发
            if (minDist[from] != INT_MAX && minDist[to] > minDist[from] + price) { 
                minDist[to] = minDist[from] + price;  
            }
        }
    }
    if (minDist[end] == INT_MAX) cout << "unconnected" << endl; // 不能到达终点
    else cout << minDist[end] << endl; // 到达终点最短路径

}

C++题解2(来源代码随想录):SPFA

对 上一次松弛的时候更新过的节点作为出发节点所连接的边 进行松弛。用队列来记录。

在加入队列的过程可以有一个优化,用visited数组记录已经在队列里的元素,已经在队列的元素不用重复加入

 基于队列优化的算法,要比bellman_ford 算法 减少很多无用的松弛情况,特别是对于边数众多的大图 优化效果明显。

每次都要知道 一个节点作为出发点连接了哪些节点。如果想方便知道这些数据,就需要使用邻接表来存储这个图

#include <iostream>
#include <vector>
#include <queue>
#include <list>
#include <climits>
using namespace std;

struct Edge { //邻接表
    int to;  // 链接的节点
    int val; // 边的权重

    Edge(int t, int w): to(t), val(w) {}  // 构造函数
};


int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;

    vector<list<Edge>> grid(n + 1); 

    vector<bool> isInQueue(n + 1); // 加入优化,已经在队里里的元素不用重复添加

    // 将所有边保存起来
    for(int i = 0; i < m; i++){
        cin >> p1 >> p2 >> val;
        // p1 指向 p2,权值为 val
        grid[p1].push_back(Edge(p2, val));
    }
    int start = 1;  // 起点
    int end = n;    // 终点

    vector<int> minDist(n + 1 , INT_MAX);
    minDist[start] = 0;

    queue<int> que;
    que.push(start); 

    while (!que.empty()) {

        int node = que.front(); que.pop();
        isInQueue[node] = false; // 从队列里取出的时候,要取消标记,我们只保证已经在队列里的元素不用重复加入
        for (Edge edge : grid[node]) {
            int from = node;
            int to = edge.to;
            int value = edge.val;
            if (minDist[to] > minDist[from] + value) { // 开始松弛
                minDist[to] = minDist[from] + value; 
                if (isInQueue[to] == false) { // 已经在队列里的元素不用重复添加
                    que.push(to);
                    isInQueue[to] = true;
                }
            }
        }

    }
    if (minDist[end] == INT_MAX) cout << "unconnected" << endl; // 不能到达终点
    else cout << minDist[end] << endl; // 到达终点最短路径
}

### 关于 KamaCoder 站的功能与特点 KamaCoder 是一个专注于 ACM 模式练习的学习平台,旨在帮助编程爱好者提升算法能力和熟悉常见数据结构的操作[^1]。该站由知名算法博主代随想录创建,提供了一系列精选的 25 道题目,这些题目覆盖了多种核心知识点,包括但不限于数组、链表、树、图等基础数据结构以及动态规划、贪心算法等多种经典算法。 #### 功能概述 - **多语言支持**:KamaCoder 提供 C++、Java、Python 和 C 四种主流编程语言的支持,允许用户自由选择熟悉的开发环境来解决问题。 - **在线评测系统**:用户可以提交自己的解决方案,并获得即时反馈,查看运行时间、内存消耗以及其他性能指标的结果分析。 - **社区互动**:除了个人练习外,还可以浏览其他用户的解答思路及其优化建议,从而促进交流学习氛围。 此外,未来计划中的笔记将进一步扩展其教育价值,成为代随想录知识星球内的一个重要组成部分。它不仅能够满足基本技能训练需求,还将引导学员深入参与到实际项目的建设过程中去——即打造属于他们自己的个性化学习空间,在那里完成技术文档整理和技术面试准备等工作的同时也增强了动手实践的能力[^2]。 对于希望提高自己编技巧或者备战各类程序设计竞赛的朋友来说,这无疑是一个非常值得尝试的好地方! ```python # 示例代展示如何利用并查集解决路径查找问题 class UnionFind: def __init__(self, n): self.parent = list(range(n)) def find(self, u): if self.parent[u]!=u: self.parent[u]=self.find(self.parent[u]) return self.parent[u] def join(self,u,v): pu,pv=self.find(u),self.find(v) if pu==pv:return False self.parent[pu]=pv return True def isSame(self,u,v): return self.find(u)==self.find(v) uf=UnionFind(10) # 初始化大小为10的并查集实例 print(uf.join(1,2)) # 将节点1和2连接起来 print(uf.isSame(1,2)) # 判断节点1和2是否在同一集合中 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值