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正是帮助我们实现这一需求的利器。下面我将通过一个简单的例子,…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...