当前位置: 首页 > news >正文

代码随想录算法训练营第五十二天

卡码网题目:

  • 94. 城市间货物运输 I
  • 95. 城市间货物运输 II
  • 96. 城市间货物运输 III

其他:

今日总结
往期打卡


算法对比

  • BellmanFord
    BellmanFord算法的思想如下
    在一个包含n个节点的图中,任意两个节点之间的最短简单路径最多包含n-1条边(经过n-2个中间节点)。因为如果路径包含超过n-1条边,必然会重复经过某个节点,形成环。
    没有中间节点一次更新就可以解决,如果有m-2个中间节点,在最后一个中间节点的基础上再更新一次也一定能解决
    根据这个性质可以先遍历n-1次更新完所有节点,再遍历n-1次确保负环传递给所有节点(一共n个节点,负环的长度加到自己的路径也不会超过n-1)
  • SPFA
    SPFA算法,算是BellmanFord算法的优化,不需要固定的n次迭代次数只要迭代完成即可终止
    SPFA算法是用队列不断遍历节点,只要不再有节点更新自然就能停止,如果有负环,就需要计数,利用节点长度不超过n可得,第n次遍历到自己,宣布有负环,之后可以bfs搜索所有本节点之后的点全部更新为负无穷.
    (每次遍历自己都会遍历到自己之前的节点,无论自己之前的节点有多少,剩余都会再遍历n-k-1次,足够更新完剩余可能的路径,将最小距离传递到当前,所以n-1次可以更新完成,多一次都说明有负环)

94. 城市间货物运输 I

跳转: 94. 城市间货物运输 I

学习: 代码随想录公开讲解

问题:

某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。

网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。

请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。

城市 1 到城市 n 之间可能会出现没有路径的情况,同时保证道路网络中不存在任何负权回路。

思路:

这里使用SPFA,不存在负环无需计数判断

复杂度:

  • 时间复杂度: O ( k n m n ) O(kn~mn) O(kn mn)
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)

代码:

import java.util.*;
class Main{public static void main(String[] args){int INF = 0x3f3f3f3f;Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int[] head = new int[n + 1],e = new int[m],next = new int[m],weight = new int[m];Arrays.fill(head,-1);// List<Edge> list = new ArrayList<>();for(int i = 0;i < m;i++){int u = scanner.nextInt();int v = scanner.nextInt();int w = scanner.nextInt();// list.add(new Edge(u,v,w));{next[i] = head[u];head[u] = i;weight[i] = w;e[i] = v;}}int[] dist = new int[n + 1];Arrays.fill(dist,INF);dist[1] = 0;Queue<Integer> queue = new LinkedList<>();queue.offer(1);while(!queue.isEmpty()){int tmp = queue.poll();for(int i = head[tmp];i != -1;i = next[i]){int j = e[i];int newDist = weight[i] + dist[tmp];if(dist[j] > newDist){dist[j] = newDist;queue.offer(j);}}}int ans = dist[n];System.out.println(ans >= INF/2 ? "unconnected" : ans);scanner.close();}
}

95. 城市间货物运输 II

跳转: 95. 城市间货物运输 II

学习: 代码随想录公开讲解

问题:

某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。

网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。

然而,在评估从城市 1 到城市 n 的所有可能路径中综合政府补贴后的最低运输成本时,存在一种情况:图中可能出现负权回路。负权回路是指一系列道路的总权值为负,这样的回路使得通过反复经过回路中的道路,理论上可以无限地减少总成本或无限地增加总收益。为了避免货物运输商采用负权回路这种情况无限的赚取政府补贴,算法还需检测这种特殊情况。

请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。同时能够检测并适当处理负权回路的存在。

城市 1 到城市 n 之间可能会出现没有路径的情况

思路:

这里有负环的情况下只需要检测到负环即可,直接BellmanFord没有负环是两遍n-1(因为负环最长可能n-1,要走一圈才能再更新)用SPFA就无需BFS遍历,第一次碰到计数到n要入队即可返回.
这里使用SPFA

复杂度:

  • 时间复杂度: O ( k n m n ) O(kn~mn) O(kn mn)
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m)

代码:

import java.util.*;class Main {public static void main(String[] args) {int INF = 0x3f3f3f3f;Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int[] head = new int[n + 1], e = new int[m], next = new int[m], weight = new int[m];Arrays.fill(head, -1);for (int i = 0; i < m; i++) {int u = scanner.nextInt();int v = scanner.nextInt();int w = scanner.nextInt();{next[i] = head[u];head[u] = i;weight[i] = w;e[i] = v;}}int[] dist = new int[n + 1];int[] cnt = new int[n + 1];Arrays.fill(dist, INF);dist[1] = 0;cnt[1]++;Queue<Integer> que = new LinkedList<>();que.offer(1);while (!que.isEmpty()) {int tmp = que.poll();for (int i = head[tmp]; i != -1; i = next[i]) {int j = e[i];if (dist[j] == -INF) continue;int newDist = weight[i] + dist[tmp];if (dist[j] > newDist) {dist[j] = newDist;que.offer(j);cnt[j]++;if (cnt[j] == n) {System.out.println("circle");return;}}}}int ans = dist[n];System.out.println(ans >= INF / 2 ? "unconnected" : ans);scanner.close();}
}

96. 城市间货物运输 III

跳转: 96. 城市间货物运输 III

学习: 代码随想录公开讲解

问题:

某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。

网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。

请计算在最多经过 k 个城市的条件下,从城市 src 到城市 dst 的最低运输成本。

思路:

单源(唯一起点终点)有限(最长路径长度有限)最短路
要确保每遍遍历只更新1层路径,所以需要复制好更新前的距离,避免基于更新更新.

这题如果直接用BellmanFord算法遍历k遍即可
如果使用SPFA需要注意队列判空,可以增加访问标记防止重复加入

复杂度:

  • 时间复杂度: O ( k m ) O(km) O(km)
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)

代码(BellmanFord):

import java.util.*;class Main {public static void main(String[] args) {int INF = 0x3f3f3f3f;Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int[] head = new int[n + 1], w = new int[m], next = new int[m], e = new int[m];Arrays.fill(head, -1);for (int i = 0; i < m; i++) {int u = scanner.nextInt();int v = scanner.nextInt();int weight = scanner.nextInt();{w[i] = weight;e[i] = v;next[i] = head[u];head[u] = i;}}int scr = scanner.nextInt();int dst = scanner.nextInt();int k = scanner.nextInt();int[] dist = new int[n + 1];Arrays.fill(dist, INF);dist[scr] = 0;Queue<Integer> queue = new LinkedList<>();queue.offer(scr);while(k-- >= 0&& !queue.isEmpty()) {int len = queue.size();int[] dist_copy = Arrays.copyOf(dist, n + 1);boolean[] vis = new boolean[n + 1];while (len-- > 0) {int h = queue.poll();for (int j = head[h]; j != -1; j = next[j]) {int cur = e[j];int tmp = w[j] + dist_copy[h];if (dist[cur] > tmp) {dist[cur] = tmp;if(vis[cur]) continue;vis[cur] = true;queue.offer(cur);}}}}System.out.println(dist[dst] >= INF / 2 ? "unreachable" : dist[dst]);}
}

复杂度:

  • 时间复杂度: O ( k m ) O(km) O(km)
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)

代码(SPFA):

import java.util.*;class Main {public static void main(String[] args) {int INF = 0x3f3f3f3f;Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int[] head = new int[n + 1], w = new int[m], next = new int[m], e = new int[m];Arrays.fill(head, -1);for (int i = 0; i < m; i++) {int u = scanner.nextInt();int v = scanner.nextInt();int weight = scanner.nextInt();{w[i] = weight;e[i] = v;next[i] = head[u];head[u] = i;}}int scr = scanner.nextInt();int dst = scanner.nextInt();int k = scanner.nextInt();int[] dist = new int[n + 1];Arrays.fill(dist, INF);dist[scr] = 0;Queue<Integer> queue = new LinkedList<>();queue.offer(scr);while(k-- >= 0&& !queue.isEmpty()) {int len = queue.size();int[] dist_copy = Arrays.copyOf(dist, n + 1);boolean[] vis = new boolean[n + 1];while (len-- > 0) {int h = queue.poll();for (int j = head[h]; j != -1; j = next[j]) {int cur = e[j];int tmp = w[j] + dist_copy[h];if (dist[cur] > tmp) {dist[cur] = tmp;if(vis[cur]) continue;vis[cur] = true;queue.offer(cur);}}}}System.out.println(dist[dst] >= INF / 2 ? "unreachable" : dist[dst]);}
}

总结

今天练习了无负环,有负环和单源有限最短路问题.

往期打卡

代码随想录算法训练营第五十一天

代码随想录算法训练营第五十天

代码随想录算法训练营第四十九天

代码随想录算法训练营第四十八天

代码随想录算法训练营第四十六&四十七天

代码随想录算法训练营第四十五天

代码随想录算法训练营第四十四天

代码随想录算法训练营第四十二&四十三天

代码随想录算法训练营第四十一天

代码随想录算法训练营第四十天

代码随想录算法训练营第三十九天

代码随想录算法训练营第三十八天

代码随想录算法训练营第三十七天

代码随想录算法训练营第三十五&三十六天

代码随想录算法训练营第三十四天

代码随想录算法训练营第三十三天(补)

代码随想录算法训练营第三十二天

代码随想录算法训练营第三十一天

代码随想录算法训练营第三十天(补)

代码随想录算法训练营第二十九天

代码随想录算法训练营第二十八天

代码随想录算法训练营第二十七天(补)

代码随想录算法训练营第二十六天

代码随想录算法训练营第二十五天

代码随想录算法训练营第二十四天

代码随想录算法训练营第二十三天

代码随想录算法训练营周末四

代码随想录算法训练营第二十二天(补)

代码随想录算法训练营第二十一天

代码随想录算法训练营第二十天

代码随想录算法训练营第十九天

代码随想录算法训练营第十八天

代码随想录算法训练营第十七天

代码随想录算法训练营周末三

代码随想录算法训练营第十六天

代码随想录算法训练营第十五天

代码随想录算法训练营第十四天

代码随想录算法训练营第十三天

代码随想录算法训练营第十二天

代码随想录算法训练营第十一天

代码随想录算法训练营周末二

代码随想录算法训练营第十天

代码随想录算法训练营第九天

代码随想录算法训练营第八天

代码随想录算法训练营第七天

代码随想录算法训练营第六天

代码随想录算法训练营第五天

代码随想录算法训练营周末一

代码随想录算法训练营第四天

代码随想录算法训练营第三天

代码随想录算法训练营第二天

代码随想录算法训练营第一天

相关文章:

  • 无法删除/重装VirtualBox,提示缺少msi安装包
  • 【系统架构设计师】2025年上半年真题论文回忆版: 论事件驱动架构及应用(包括解题思路和参考素材)
  • 中望CAD与AutoCAD的SWOT对比分析(基于2025线上发布会观察与行业数据)
  • 最终章:终焉之塔 · 前端之道
  • Telnet 命令详解
  • 传感器技术的演进与测试方法探究
  • 【设计模式】责任链
  • Ubuntu 系统grub日志级别设置
  • 专业课复习笔记 10
  • Rust 学习笔记:循环和迭代器的性能比较
  • MySQL 表内容的增删查改 -- CRUD操作,聚合函数,group by 子句
  • 期货反向跟单—交易规则设计(四)品种选择
  • 火热邀测!DataWorks数据集成支持大模型AI处理
  • vue3+element plus 自定义组件,单列的方块 图形加文字列表
  • Cursor:开启智能编程新视界
  • DeepSpeed常见面试问题
  • Unity屏幕适配——背景适配
  • 微前端架构设计与实战示例
  • 小白的进阶之路系列之四----人工智能从初步到精通pytorch自定义数据集下
  • 【数据库】概述(纯理论)
  • 网站设计心得/最新新闻热点话题
  • 峨眉住房和城乡建设委员会网站/整合营销传播策划方案
  • 外贸整合营销网站/seo域名综合查询
  • 珠海商城网站/短视频运营培训学费多少
  • 双色调网站/护肤品营销策划方案
  • 能自己做头像的网站/如何建网站详细步骤