Day62 图论part11
Floyd 算法精讲
Floyd 算法代码很简单,但真正理解起原理 还是需要花点功夫,大家在看代码的时候,会发现 Floyd 的代码很简单,甚至看一眼就背下来了,但我为了讲清楚原理,本篇还是花了大篇幅来讲解。
代码随想录
方法1:三维dp数组
import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();int[][][] grid = new int[n+1][n+1][n+1];//grid[i][j][k] = m 表示节点i 到 j ,以[1...k] 集合为中间节点的最短距离为mfor(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){Arrays.fill(grid[i][j], Integer.MAX_VALUE);} grid[i][i][0] = 0;}for(int i = 0; i < m; i++){int u = sc.nextInt();int v = sc.nextInt();int w = sc.nextInt();grid[u][v][0] = w;grid[v][u][0] = w;}for(int k = 1; k <= n; k++){for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){if(grid[i][k][k-1] != Integer.MAX_VALUE && grid[k][j][k-1] != Integer.MAX_VALUE){grid[i][j][k] = Math.min(grid[i][j][k-1], grid[i][k][k-1]+grid[k][j][k-1]);}else{grid[i][j][k] = grid[i][j][k-1];// grid[i][j][k]并不会继承grid[i][j][k-1],而是保留为初始值;}}}}int q = sc.nextInt();for(int i = 0; i < q; i++){int start = sc.nextInt();int end = sc.nextInt();if(grid[start][end][n] == Integer.MAX_VALUE){System.out.println(-1);}else{System.out.println(grid[start][end][n]); }}}} 方法2:二维dp数组
import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();int[][] grid = new int[n+1][n+1];//grid[i][j][k] = m 表示节点i 到 j ,以[1...k] 集合为中间节点的最短距离为mfor(int i = 1; i <= n; i++){Arrays.fill(grid[i], 10001);grid[i][i] = 0;}for(int i = 0; i < m; i++){int u = sc.nextInt();int v = sc.nextInt();int w = sc.nextInt();grid[u][v] = w;grid[v][u] = w;}for(int k = 1; k <= n; k++){for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){grid[i][j] = Math.min(grid[i][j], grid[i][k]+grid[k][j]);}}}int q = sc.nextInt();for(int i = 0; i < q; i++){int start = sc.nextInt();int end = sc.nextInt();if(grid[start][end] == 10001){System.out.println(-1);}else{System.out.println(grid[start][end]); }}}} 总结
1.确定dp数组(dp table)以及下标的含义:
//grid[i][j][k] = m 表示节点i 到 j ,以[1...k] 集合为中间节点的最短距离为m2
2.确定递推公式
第一种情况:不经过中间节点K,那么
grid[i][j][k] = grid[i][j][k-1]
第二种情况:经过中间节点K,那么
grid[i][j][k] = grid[i][k][k-1]+grid[k][j][k-1];
节点i 到 节点k 的最短距离 是不经过节点k,中间节点集合为[1...k-1],所以 表示为grid[i][k][k - 1]
节点k 到 节点j 的最短距离 也是不经过节点k,中间节点集合为[1...k-1],所以表示为 grid[k][j][k - 1]
grid[i][j][k] = Math.min(grid[i][j][k-1], grid[i][k][k-1]+grid[k][j][k-1]);
3.dp数组如何初始化:需要初始化K=0的情况,K=0,就是两个节点直接相连,没有中间节点,所以直接赋值边的权值就可以了(双向或者无向需要两个方向初始化,有向图只要一个方向初始化)。然后其他对角元素应该初始化为0,其他元素初始化为边的权值的最大值(10001或者最大整形都可以,10001更加方便,后续不需要考虑溢出的情况)。
4.确定遍历顺序:
grid[i][j][k] = Math.min(grid[i][j][k-1], grid[i][k][k-1]+grid[k][j][k-1]);
初始化的时候把 k =0 的 i 和j 对应的数值都初始化了,这样才能去计算 k = 1 的时候 i 和 j 对应的数值。这就好比是一个三维坐标,i 和j 是平层,而k是垂直向上的。遍历的顺序是从底向上 一层一层去遍历。所以遍历k 的for循环一定是在最外面,这样才能一层一层去遍历。k 依赖于 k - 1, i 和j 的到并不依赖与 i - 1 或者 j - 1 。所以一定是把k 的for循环放在最外面,才能用上 初始化和上一轮计算的结果了。i和j的遍历顺序就无所谓了。
5.二维的dp数组,就把k这一维度去掉。每次进入新的k,其实都保留着上一轮k的数值,靠着最外层的for循环,来实现对k的滚动。
6.Floyd 算法的时间复杂度相对较高,Floyd 算法适合多源最短路,即 求多个起点到多个终点的多条最短路径。适合 稠密图且源点较多的情况。时间复杂度: O(n^3);如果 源点少,其实可以 多次dijsktra 求源点到终点。Floyd 算法对边的权值正负没有要求,都可以处理。
A * 算法精讲 (A star算法)
一般 笔试或者 面试的时候,不会考察A*, 都是会结合具体业务场景问 A*算法,例如:地图导航,游戏开发 等等。其实基础版的A* 并不难,所以大家不要畏惧,理解本篇内容,甚至独立写出代码,大家可以做到,加油
A * 算法精讲 (A star算法) | 代码随想录
import java.util.*;public class Main {static int[][] moves = new int[1001][1001]; // 记录每个位置的移动次数static int[][] dir = { // 马的8个方向{-2, -1}, {-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}};static int b1, b2; // 目标位置的x, y坐标static class Knight implements Comparable<Knight> {int x, y, g, h, f;Knight(int x, int y, int g, int h) {this.x = x;this.y = y;this.g = g; // G = 从起点到该节点的路径消耗this.h = h; // H = 从该节点到终点的预估消耗this.f = g + h; // F = G + H}@Overridepublic int compareTo(Knight k) {return Integer.compare(this.f, k.f); // 按照f值从小到大排序}}// 欧拉距离的启发函数(不开根号以提高精度)static int heuristic(Knight k) {return (k.x - b1) * (k.x - b1) + (k.y - b2) * (k.y - b2);}static void astar(Knight start) {PriorityQueue<Knight> queue = new PriorityQueue<>();queue.add(start);while (!queue.isEmpty()) {Knight cur = queue.poll(); // 取出f值最小的节点// 如果到达目标位置,直接退出if (cur.x == b1 && cur.y == b2) {break;}for (int[] d : dir) {int nx = cur.x + d[0];int ny = cur.y + d[1];// 检查边界if (nx < 1 || nx > 1000 || ny < 1 || ny > 1000) {continue;}// 如果这个位置没有访问过if (moves[nx][ny] == 0) {moves[nx][ny] = moves[cur.x][cur.y] + 1; // 更新移动次数int g = cur.g + 5; // 马走日消耗固定为5int h = heuristic(new Knight(nx, ny, 0, 0));Knight next = new Knight(nx, ny, g, h);queue.add(next); // 加入优先队列}}}}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(); // 测试案例数量while (n-- > 0) {int a1 = sc.nextInt(), a2 = sc.nextInt(); // 起点坐标b1 = sc.nextInt();b2 = sc.nextInt(); // 终点坐标for (int[] row : moves) {Arrays.fill(row, 0); // 初始化moves数组}Knight start = new Knight(a1, a2, 0, heuristic(new Knight(a1, a2, 0, 0)));astar(start);System.out.println(moves[b1][b2]); // 输出结果}sc.close();}
} PriorityQueue<Knight> queue = new PriorityQueue<>();这个PriorityQueue 自动根据 compareTo 方法维护堆的性质或任何自定义比较器的实现。
@Overridepublic int compareTo(Person other) {return Integer.compare(this.age, other.age); // 按年龄升序排序}//反向比较
@Override
public int compareTo(Knight k) {return Integer.compare(k.f, this.f); // 交换位置,k 在前面
}
1.为什么按照 F 值排序?
- F = G + H 表示从起点经过当前节点到终点的总代价估计值。
- 按照 F 值排序能够保证优先探索 当前预估代价最小的路径,从而以最快的速度找到最优解。
示例解释
假设:
- 当前节点 A 的 G=2, H=5, 所以 F=2+5=7。
- 另一个节点 B 的 G=4, H=2, 所以 F=4+2=6。
如果只按照 H 值排序,会优先选择 A(H = 5):
- 但 A 的总代价 F=7,并不是最优路径。
按照 F 值排序,会优先选择 B(F = 6),更接近最终的最优路径。
核心思路就是从队列里面优先弹出F值更小的元素,那么使用优先级队列就可以做到。Java 的优先级队列 (PriorityQueue) 默认是小顶堆。这意味着在队列中,优先级最低的元素(数值最小的元素)会排在队首,即最先被弹出。
2.moves 数组的作用是 记录某个棋盘位置是否已经访问过,以及该位置从起点到当前的 步数。
3.Astar 是一种 广搜的改良版。 或者是 dijkstra 的改良版。如果是无权图(边的权值都是1) 那就用广搜。如果是有权图(边有不同的权值),优先考虑 dijkstra。Astar 关键在于 启发式函数, 也就是 影响 广搜或者 dijkstra 从 容器(队列)里取元素的优先顺序。
最短路算法总结篇
最各个最短路算法有个全面的了解
最短路算法总结篇 | 代码随想录
图论总结
图论总结篇 | 代码随想录
相关文章:
Day62 图论part11
Floyd 算法精讲 Floyd 算法代码很简单,但真正理解起原理 还是需要花点功夫,大家在看代码的时候,会发现 Floyd 的代码很简单,甚至看一眼就背下来了,但我为了讲清楚原理,本篇还是花了大篇幅来讲解。 代码随想…...
git clone 超时
git clone 超时 参考 https://blog.csdn.net/qq_45906972/article/details/142214187?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-142214187-blog-137158358.235v43pc_blog_bottom_relevance_base8&spm1001.2101.3001.…...
WPF编程excel表格操作
WPF编程excel表格操作 摘要NPOI安装封装代码测试代码 摘要 Excel操作几种方式 使用开源库NPOI(常用,操作丰富)使用Microsoft.Office.Interop.Excel COM组件(兼容性问题)使用OpenXml(效率高)使用OleDb(过时) NPOI安装 封装代码 using System; using System.IO; u…...
Day10补代码随想录 理论基础|232.用栈实现队列|225.用队列实现栈|20.有效的括号|1047.删除字符串中的所有相邻重复项
栈和队列理论基础 抽象认识 栈是先进后出(FIFO),队列是先进先出(LIFO) 队首(先进))队尾(后进)栈顶(后进)栈底(先进) 栈(Stack) 只在一端进行进出操作(只在一端进一端出)像个篮球框,取用篮球从一端进出。 /进栈 int a[1000];//足够大的栈空间 int top-1…...
【Devops】什么是Devops?(Development+Operations)和运维的区别?
DevOps(Development Operations)是一种将开发(Development)和运维(Operations)团队结合在一起的文化和实践,目的是通过自动化、协作和持续反馈来加快软件的开发、部署和运维的周期,…...
基于NodeMCU的物联网电灯控制系统设计
最终效果 基于NodeMCU的物联网电灯控制系统设计 小程序关灯 上图展现了小程序关灯过程的数据传输过程:用户下达关灯指令→小程序下发关灯指令→MQTT服务器接收关灯指令→下位机接收与处理关灯指令。 项目介绍 该项目是“物联网实验室监测控制系统设计(…...
Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02
在嵌入式开发中,I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于与外设(如 EEPROM、传感器、显示屏等)进行数据交换。AT24C02 是一种常见的 I2C EEPROM 存储器,它提供 2Kbit…...
Linux应用软件编程-多任务处理(线程)
线程:轻量级的进程,线程的栈区独立(8M),与同一进程中的其他线程共用进程的堆区,数据区,文本区。 进程是操作系统资源分配的最小单位;线程是cpu任务调度的最小单位。 1. 线程的创建…...
VITUREMEIG | AR眼镜 算力增程
根据IDC发布的《2024年第三季度美国AR/VR市场报告》显示,美国市场AR/VR总出货量增长10.3%。其中,成立于2021年的VITURE增长速度令人惊艳,同比暴涨452.6%,成为历史上增长最快的AR/VR品牌。并在美国AR领域占据了超过50%的市场份额&a…...
Jenkins管理多版本python环境
场景:项目有用到python3.8和3.9,python环境直接安装在jenkins容器内。 1、进入jenkins容器 docker exec -it jenkins /bin/bash 2、安装前置编译环境 # 提前安装,以便接下来的配置操作 apt-get -y install gcc automake autoconf libtool ma…...
Flutter富文本实现学习
Flutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件,而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能,比如在富文本…...
如何解决 OpenAI API 连接问题:降级 urllib3 版本
如何解决 OpenAI API 连接问题:降级 urllib3 版本 在使用 OpenAI API 时,很多开发者可能会遇到连接问题,特别是在使用 Python 代码与 OpenAI 进行交互时。常见的错误包括 ProxyError、SSLError 和 MaxRetryError,它们通常表示在通…...
【C语言】库函数常见的陷阱与缺陷(三):内存分配函数[4]--free
C语言中的free函数用于释放之前通过malloc、calloc或realloc动态分配的内存。然而,在使用free函数时,开发者可能会遇到一些陷阱和缺陷。 一、功能与用法 free 函数是 C 语言中用于释放动态分配内存的关键函数。在程序使用 malloc、calloc 或 realloc 等函数在堆上分配了内存…...
论文分享 | PromptFuzz:用于模糊测试驱动程序生成的提示模糊测试
大语言模型拥有的强大能力可以用来辅助多种工作,但如何有效的辅助仍然需要人的精巧设计。分享一篇发表于2024年CCS会议的论文PromptFuzz,它利用模型提示生成模糊测试驱动代码,并将代码片段嵌入到LLVM框架中执行模糊测试。 论文摘要 制作高质…...
AWS K8s 部署架构
Amazon Web Services(AWS)提供了一种简化的Kubernetes(K8s)部署架构,使得在云环境中管理和扩展容器化应用变得更加容易。这个架构的核心是AWS EKS(Elastic Kubernetes Service),它是…...
JavaSE笔记(四)
Java泛型与集合类 在前面我们学习了最重要的类和对象,了解了面向对象编程的思想,注意,非常重要,面向对象是必须要深入理解和掌握的内容,不能草草结束。在本章节,我们会继续深入了解,从我们的泛型开始,再到我们的数据结构,最后再开始我们的集合类学习。 走进泛型 为…...
C语言基础——指针(5)
一. 函数指针变量 1. 函数指针变量的定义: 类比数组指针变量,数组指针变量是存放数组地址的变量,那么同理,函数指针变量就是存放函数地址的变量。 2. 创建函数指针变量: 函数是有地址的࿰…...
curl+openssl 踩坑笔记
curl编译:点击跳转 踩坑一 * SSL certificate problem: unable to get local issuer certificate * closing connection #0 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html …...
Unity 实现Canvas显示3D物体
新建一个UI相机,选择渲染层为UI 将主相机的渲染层去掉UI层 、 将Canvas的RenderMode设置为Screen Space - Camera,将RenderCamera设置为UI相机 新建3D物体的UI父物体,并将3D物体的层级设置为UI层 适当的放缩3DObjParent,让3D物体能显示出来…...
【Docker命令】如何使用`docker exec`在容器内执行命令
大家好,今天我们来聊聊Docker容器管理中的一个非常有用的命令:docker exec。在日常工作中,我们经常需要在运行中的Docker容器内执行各种命令,docker exec正是帮助我们实现这一需求的利器。下面我将通过一个简单的例子,…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
无需布线的革命:电力载波技术赋能楼宇自控系统-亚川科技
无需布线的革命:电力载波技术赋能楼宇自控系统 在楼宇自动化领域,传统控制系统依赖复杂的专用通信线路,不仅施工成本高昂,后期维护和扩展也极为不便。电力载波技术(PLC)的突破性应用,彻底改变了…...
python数据结构和算法(1)
数据结构和算法简介 数据结构:存储和组织数据的方式,决定了数据的存储方式和访问方式。 算法:解决问题的思维、步骤和方法。 程序 数据结构 算法 算法 算法的独立性 算法是独立存在的一种解决问题的方法和思想,对于算法而言&a…...
盲盒一番赏小程序:引领盲盒新潮流
在盲盒市场日益火爆的今天,如何才能在众多盲盒产品中脱颖而出?盲盒一番赏小程序给出了答案,它以创新的玩法和优质的服务,引领着盲盒新潮流。 一番赏小程序的最大特色在于其独特的赏品分级制度。赏品分为多个等级,从普…...
