【代码随想录day58】【C++复健】 117. 软件构建(拓扑排序);47. 参加科学大会(dijkstra(朴素版)精讲)
117. 软件构建(拓扑排序)
继续边看解析边做题,思考时的问题做个如下的总结:
1. 存边用什么数据结构?
在题目中,我们需要存储节点之间的依赖关系(边信息)。选择适合的数据结构非常重要:
- 选择
unordered_map<int, vector<int>>
:- 这个结构的作用是将节点
int
映射到一个vector<int>
,即以 O(1) 的复杂度找到所有依赖当前节点的节点集合。 - 在代码中,
rela[left].push_back(right)
表示从节点left
指向节点right
的边。
- 这个结构的作用是将节点
这种结构方便快捷,是处理稀疏图的常见选择。如果用二维数组存储,虽然逻辑上也可以,但会浪费内存并导致效率下降。
2 队列是否需要初始化代码?
自己思考的时候感觉队列需要一个初始化代码,但是却想不明白能不能合到主循环的代码里面去。看了卡哥的解析之后发现了,并不能,所以无须担心。
3 循环逻辑问题(GPT优化版)
我在写这道题时,曾经因为对循环逻辑的处理不当导致代码变成了死循环。具体问题是,我把初始化代码直接搬到了主循环里,导致一些节点被重复插入队列。比如,节点 1 在初始化时已经被插入队列了,但后面又因为错误的逻辑反复地被插入队列,这显然是不正确的。
当时我的想法是,在节点进入队列后,把它对应的 indegree
值设置成 -1,这样能避免重复插入。但是后来忘记实现这一点,结果还是出现了问题。虽然这种方式能够解决问题,但仔细想想,其实有更简单的方法:只要在 indegree[tominus[i]]--;
这一步之后,立即判断节点的入度是否减到 0,如果是 0,就将它加入队列。
这样处理有两个明显的优点:
- 避免重复插入节点: 减少入度操作的节点必然是与其他节点存在依赖关系的(即入度不为 0 的节点),只有在入度变为 0 时才会被加入队列,从逻辑上保证了节点最多只会入队一次。
- 减少不必要的遍历: 在减少入度时直接判断是否需要入队,避免了每次操作后全量扫描所有节点,显著提高了代码效率。
最终通过这样的调整,不仅解决了死循环问题,还让代码的逻辑更加清晰,执行效率也更高。这种在操作中即时判断的优化思路,给我很大的启发。
#include<iostream>
#include<vector>
#include<queue>
#include<unordered_map>
using namespace std;int main(){int n,m;cin >> n >> m;vector<int> indegree(n);vector<int> result;unordered_map<int, vector<int>> rela;for(int i=0; i<m; i++){int left, right;cin >> left >> right;indegree[right]++;rela[left].push_back(right);}queue<int> zerodegree;for(int i=0; i<n; i++){if(indegree[i] == 0){zerodegree.push(i);}}while(!zerodegree.empty()){int top = zerodegree.front();zerodegree.pop();result.push_back(top);vector<int> tominus = rela[top];for(int i=0; i<tominus.size(); i++){indegree[tominus[i]]--;if (indegree[tominus[i]] == 0) {zerodegree.push(tominus[i]);}}}if(result.size() == n){for(int i=0; i<n; i++){cout << result[i];if(i<n-1){cout << " ";}}return 0;}cout << -1;
}
47. 参加科学大会(dijkstra(朴素版)精讲)
虽然的确是第一次写最短路算法,也是边看着解析边做的,但确实感觉这个题和prim算法非常的像,只要稍微改一下更新的公式就行,自信就来了。
然后自己上手一写,一塌糊涂。
来看GPT给我分析的问题:
1. 未初始化输入的边信息
在读取边信息时,你直接将 distance[left][right] = val
,但没有先读取 left
和 right
,会导致程序读取未定义的值。
修正方法: 在读取边之前,添加 cin >> left >> right >> val
:
for (int i = 0; i < m; i++) {int left, right, val;cin >> left >> right >> val; // 读取边信息distance[left][right] = val;distance[right][left] = val;
}
并且这里其实还有一个更严肃的问题,那就是这是一个有向图而非无向图,所以我不能给左右赋同样的值(因为这个,做不对还想了半天),不然会导致算出来的结果不对,所以正确的应该是:
for (int i = 0; i < m; i++) {int left, right, val;cin >> left >> right >> val; // 读取边信息distance[left][right] = val;
}
2. 忘了在计算距离最小值的判断力加入对visited数组的判断
在第一个循环中,你将 visited[1]
设置为 true
,但后续并没有在循环中检查哪些节点已经被访问过,可能会导致重复访问,或者访问逻辑错误。
修正方法: 在主循环和内层循环中,增加对 visited
的判断:
if (!visited[j] && mindist[j] < dis_min) {
3. 访问越界问题
当所有节点都访问过后,pos
可能仍然是 -1
,表示当前没有未访问的节点。这会导致接下来的代码逻辑失效,导致访问出现越界问题。
修正方法: 在找到最小 pos
后立即判断:
if (pos == -1) {break; // 无法找到更短的路径,直接退出
}
顺带一提,卡哥的做法是直接给pos赋值成1,这样即使是没找到,也不会导致访问越界。但这样做的坏处在于,卡哥的这种写法会让循环继续执行,但假设我们循环一整圈都没有找到比INT_MAX更小的距离,此时其实说明已经没边了,所以循环没有必要继续执行了,直接break掉还能省点事情。
脑子里的杠精:如果刚好有一个距离就等于INT_MAX,你这个判断不就失效了吗?
emm... 那如果是这样距离总和都超过INT能表示的范围了,不如放他一马。
4. 在更新距离时也忘了对visited数组的判断
if (!visited[k] && distance[pos][k] != INT_MAX) {mindist[k] = min(mindist[pos] + distance[pos][k], mindist[k]);
}
以上就是本期的全部内容了,喜欢不要忘了点个一键三连哦(串台)
#include<iostream>
#include<vector>
#include <climits>
using namespace std;int main(){int n,m;cin >> n >> m;vector<vector<int>> distance(n+1, vector<int>(n+1, INT_MAX));for(int i=0; i<m; i++){int left, right, val;cin >> left >> right >> val;distance[left][right] = val;//distance[right][left] = val; //不能加,加了你就完了}vector<int> mindist(n+1, INT_MAX);vector<bool> visited(n+1);mindist[1] = 0;for(int i=1; i<=n; i++){int dis_min = INT_MAX;int pos = -1;for(int j=1; j<=n; j++){if(!visited[j] && mindist[j] < dis_min){dis_min = mindist[j];pos = j;}}if (pos == -1) {break; // 无法找到更短的路径,直接退出}visited[pos] = true;for(int k=1; k<=n; k++){if(!visited[k] && distance[pos][k] != INT_MAX){mindist[k] = min(mindist[pos] + distance[pos][k], mindist[k]);}}}if(mindist[n] == INT_MAX){cout << -1;return 0;}cout << mindist[n];
}
相关文章:

【代码随想录day58】【C++复健】 117. 软件构建(拓扑排序);47. 参加科学大会(dijkstra(朴素版)精讲)
117. 软件构建(拓扑排序) 继续边看解析边做题,思考时的问题做个如下的总结: 1. 存边用什么数据结构? 在题目中,我们需要存储节点之间的依赖关系(边信息)。选择适合的数据结构非常重…...

【NLP 16、实践 ③ 找出特定字符在字符串中的位置】
看着父亲苍老的白发和渐渐老态的面容 希望时间再慢一些 —— 24.12.19 一、定义模型 1.初始化模型 ① 初始化父类 super(TorchModel, self).__init__(): 调用父类 nn.Module 的初始化方法,确保模型能够正确初始化。 ② 创建嵌入层 self.embedding n…...

费解的开关(bfs + 哈希表 or 递推)
题目描述: 25盏灯排成一个5x5的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。 我们用数字“1”表示一盏开着的灯,用数字“0”表示关…...

C语言——实现求出最大值
问题描述:利用C语言自定义函数求出一维数组里边最大的数字 //利用函数找最大数#include<stdio.h>int search(int s[9]) //查找函数 {int i , max s[0] , max_xia 0;for(i0;i<9;i){if(s[i] > max){max_xia i;max s[max_xia];}}return max; } in…...

基于微信小程序的短视频系统(SpringBoot)+文档
💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...

Flutter 中 Sliver 的各种装饰器介绍与使用
在 Flutter 中,Sliver 是一种可以在滚动视图中实现自定义效果的组件。Sliver 组件可以根据滚动位置动态改变其外观和行为。本文将介绍几种常用的 Sliver 装饰器及其使用方法。 1. SliverAppBar SliverAppBar 是一个可以随着滚动而变化的应用栏。它可以在用户向下滚…...
电感的基本概念
电感的定义: 电感一般是由导线绕成空芯线圈或带铁芯的线圈而制成。 当线圈中有电流通过时,线圈周围就会产生磁场,当线圈中流过的是直流电流时,线圆周围就会产生固定的磁场,线圈产生的物理现象就是电磁铁,当…...

linux基于systemd自启守护进程 systemctl自定义服务傻瓜式教程
系统服务 书接上文: linux自启任务详解 演示系统:ubuntu 20.04 开发部署项目的时候常常有这样的场景: 业务功能以后台服务的形式提供,部署完成后可以随着系统的重启而自动启动;服务异常挂掉后可以再次拉起 这个功能在ubuntu系统中通常由systemd提供 如果仅仅需要达成上述的场…...

HTTP协议和接口测试详解
介绍接口测试前我们先来介绍一下HTTP协议,为什么先要介绍HTTP协议呢因为因为我们做接口测试其实就是用测试工具(postman,fiddler,jmeter等等)或代码来模拟用户使用软件的场景,在我们模拟的时候不像平时功能测试时我们有已经开发完…...

vue3【实战】定义全局方法(两种方案)
以全局方法 calculate 为例 src/utils/calculate.ts export default {sum: function (a: number, b: number) {return a b} }方案1: 依赖注入 provide inject main.ts import calculate from ./utils/calculateapp.provide(calculate, calculate)页面中 // esl…...

基于JavaScript的DBUtils增删改查操作实验
1、实验目的 学习和掌握数据库连接池的配置与管理。使用DBUtils进行增删改查操作。按照步骤,掌握并实现使用DBUtils实现增删改查的全过程。 2、实验所用方法 上机实践 3、实验步骤及截图 创建一个数据库表,使用下面sql语句创建数据库表并插入数据&#x…...

初学stm32 --- 系统时钟配置
众所周知,时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。于是有人要问,采用一个系统时钟不是很简单吗?为…...

实现星星评分系统
使用HTML、CSS和JavaScript实现星星评分系统 本文将详细讲解如何使用 HTML、CSS 和 JavaScript 实现一个简单的星星评分系统。用户可以通过点击星星进行评分,并且还能够看到星星的悬浮效果和已选中状态。 1. HTML 结构 我们首先在 HTML 中定义了一个星星评分的结…...

数据库建模工具 PDManer
数据库建模工具 PDManer 1.PDManer简介2.PDManer使用 1.PDManer简介 PDManer(元数建模)是一款功能强大且易于使用的开源数据库建模工具。它不仅支持多种常见数据库,如MySQL、PostgreSQL、Oracle、SQL Server等,还特别支持国产数据…...

后台运维操作建议
文章目录 1.版本升级2.配置发布3.数据库/脚本操作4.发布依赖确认5.发布规范6.服务下线参考文献 1.版本升级 版本升级是软件维护和演进中的关键环节,但它可能带来一系列问题。这些问题涉及兼容性、功能、性能、安全性等方面。 【强制】版本管理:使用版本…...

NX二次开发调用内部函数设置对象穿透显示DSS_ATTR_set_show_through
获取动态库libdisp.dll的路径 void TcharToChar(const TCHAR* tchar, char* _char) {int iLength; #if UNICODE//获取字节长度 iLength = WideCharToMultiByte(CP_ACP, 0, tchar, -1, NULL, 0, NULL, NULL);//将tchar值赋给_char WideCharToMultiByte(CP_ACP, 0, tchar, …...

ubuntu16.04ros-用海龟机器人仿真循线系统
下载安装sudo apt-get install ros-kinetic-turtlebot ros-kinetic-turtlebot-apps ros-kinetic-turtlebot-interactions ros-kinetic-turtlebot-simulator ros-kinetic-kobuki-ftdi sudo apt-get install ros-kinetic-rocon-*echo "source /opt/ros/kinetic/setup.bash…...

解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误 您在 Ubuntu 20.04 上编译 OpenCV 3.2 时遇到的错误与 C 标准库的头文件配置问题有关。错误消息指出系统无法找到 <stdlib.h>,这通常与预编译头文件的处理、GCC 版本或者头文件搜索路径有关。下面…...

HTML综合案例
为了前端考试。 效果图: HTML代码: <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…...

TanStack——为现代前端开发提供高性能和灵活的工具
TanStack 是一个由社区主导的开源项目集合,专注于为现代前端开发提供高性能和灵活的工具。它包括多个流行的 JavaScript 和 TypeScript 库,主要用于处理表格、查询、虚拟化、状态管理等功能。 文章目录 1、TanStack Query:1.1 useQuery&#…...

Java爬虫️ 使用Jsoup库进行API请求有什么优势?
在Java的世界里,Jsoup库以其强大的HTML解析能力而闻名。它不仅仅是一个简单的解析器,更是一个功能齐全的工具箱,为开发者提供了从网页抓取到数据处理的一站式解决方案。本文将深入探讨使用Jsoup库进行API请求的优势,并提供代码示例…...

React源码02 - 基础知识 React API 一览
1. JSX到JavaScript的转换 <div id"div" key"key"><span>1</span><span>2</span> </div>React.createElement("div", // 大写开头会当做原生dom标签的字符串,而组件使用大写开头时,这…...

COMSOL with Matlab
文章目录 基本介绍COMSOL with MatlabCOMSOL主Matlab辅Matlab为主Comsol为辅 操作步骤常用指令mphopenmphgeommghmeshmphmeshstatsmphnavigatormphplot常用指令mphsavemphlaunchModelUtil.clear 实例教学自动另存新档**把语法套用到边界条件**把语法套用到另存新档 函数及其微分…...

【报表查询】.NET开源ORM框架 SqlSugar 系列
文章目录 前言实践一、按月统计没有为0实践二、 统计某月每天的数量实践三、对象和表随意JOIN实践四、 List<int>和表随意JOIN实践五、大数据处理实践六、每10分钟统计Count实践七、 每个ID都要对应时间总结 前言 在我们实际开发场景中,报表是最常见的功能&a…...

PostgreSQL数据库访问限制详解
pg_hba.conf 文件是 PostgreSQL 数据库系统中非常重要的一个配置文件,它用于定义哪些用户(或客户端)可以连接到 PostgreSQL 数据库服务器,以及他们可以使用哪些认证方法进行连接。 pg_hba.conf 的名称来源于 "Host-Based Aut…...

【test linux】创建一个ext4类型的文件系统
创建一个ext4类型的文件系统 dd 是一个非常强大的命令行工具,用于在Unix/Linux系统中进行低级别的数据复制和转换。这条命令的具体参数含义如下: if/dev/zero:指定输入文件(input file)为 /dev/zero,这是一…...

如何在繁忙的生活中找到自己的节奏?
目录 一、理解生活节奏的重要性 二、分析当前生活节奏 1. 时间分配 2. 心理状态 3. 身体状况 4. 生活习惯 1. 快慢适中 2. 张弛结合 3. 与目标相符 三、掌握调整生活节奏的策略 1. 设定优先级 2. 合理规划时间 3. 学会拒绝与取舍 4. 保持健康的生活方式 5. 留出…...

AI-PR曲线
PR曲线 人工智能里面的一个小概念。 2.3 性能度量(查全率,查准率,F1,PR曲线与ROC曲线) 预测出来的是一个概率,不能根据概率来说它是正类还是负类,要有一个阈值。 查准率(Precision&…...

Guava 提供了集合操作 `List`、`Set` 和 `Map` 三个工具类
入门示例 guava 最佳实践 学习指南 以下是使用Google Guava库中的工具方法来创建和操作List、Set、Map集合的一些示例: List相关操作 创建List 使用Lists.newArrayList()创建一个新的可变ArrayList实例。List<Integer> list Lists.newArrayList(1, 2, 3);/…...

深入解析 Elasticsearch 集群配置文件参数
在自建 Elasticsearch 集群时,我们需要通过 elasticsearch.yml 文件对节点角色、网络设置、集群发现和数据存储路径等进行灵活配置。配置项的合理设置对集群的稳定性、性能与扩展性影响深远。本文将以一个示例配置文件为蓝本,逐条解析各参数的含义与建议…...