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 从 容器(队列)里取元素的优先顺序。

最短路算法总结篇

最各个最短路算法有个全面的了解

最短路算法总结篇 | 代码随想录

图论总结

图论总结篇 | 代码随想录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/500919.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】多数据源事务卡死@DSTransactional,当某一个数据库挂掉了,系统卡死问题解决

记录最近发生并解决的一个问题 原因 在一个事务内&#xff0c;操作多个数据库&#xff0c;当其中一个数据库挂掉后&#xff0c;默认无限重连&#xff0c;导致事务无法正常结束&#xff0c;导致系统卡死 解决 将无限重连改成有限次数即可 datasource:db1:driver-class-name…

迅为RK3568开发板编译Android12源码包-设置屏幕配置

在源码编译之前首先要确定自己想要使用的屏幕并修改源码&#xff0c;在编译镜像&#xff0c;烧写镜像。如下图所示&#xff1a; 第一步&#xff1a;确定要使用的屏幕种类&#xff0c;屏幕种类选择如下所示&#xff1a; iTOP-3568 开发板支持以下种类屏幕&#xff1a; 迅为 LV…

重装操作系统后 Oracle 11g 数据库数据还原

场景描述&#xff1a; 由于SSD系统盘损坏&#xff0c;更换硬盘后重装了操作系统&#xff0c;Oracle数据库之前安装在D盘(另一个硬盘)&#xff0c;更换硬盘多添加一个盘符重装系统后盘符从D变成E&#xff0c;也就是之前的D:/app/... 变成了现在的 E:/app/...&#xff0c;重新安装…

企业二要素如何用C#实现

一、什么是企业二要素&#xff1f; 企业二要素&#xff0c;通过输入统一社会信用代码、企业名称或统一社会信用代码、法人名称&#xff0c;验证两者是否匹配一致。 二、企业二要素适用哪些场景&#xff1f; 例如&#xff1a;信用与金融领域 1.信用评级&#xff1a;信用评级…

丢弃法hhhh

一个好的模型需要对输入数据的扰动鲁棒 丢弃法&#xff1a;在层之间加入噪音&#xff0c;等同于加入正则 h2和h5变成0了 dropout一般作用在全连接隐藏层的输出上 Q&A dropout随机置零对求梯度和求反向传播的影响是什么&#xff1f;为0 dropout属于超参数 dropout固定随…

shell学习数学运算符和字符串(三)

这里写目录标题 一、数学运算符1、基本语法2、expr运算3、(())4、let运算5、bc命令6、中括号[] 二、字符串1、单双引号2、字符串拼接3、获取字符串长度4、字符串提取 一、数学运算符 1、基本语法 ( ( ) ) 或者 (())或者 (())或者{}expr ,-,*,/,%加减乘除取余 2、expr运算 ex…

【Java设计模式-1】单例模式,Java世界的“独苗”

今天咱们要一起探秘Java设计模式中的一个超级有趣又超级实用的家伙——单例模式。想象一下&#xff0c;在Java的代码王国里&#xff0c;有这么一类特殊的存在&#xff0c;它们就像独一无二的“独苗”&#xff0c;整个王国里只允许有一个这样的家伙存在&#xff0c;这就是单例模…

无人机飞手培训机构大量新增,考取飞手证参军入伍还有优势吗?

尽管无人机飞手培训机构大量新增&#xff0c;考取飞手证参军入伍仍然具有显著优势。以下是对这一观点的详细阐述&#xff1a; 一、无人机飞手证在军队中的通用优势 1. 法规遵从与安全保障&#xff1a; 根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关法规&#xff0…

计算机网络原理(一)

嘿&#xff01; 新年的第一篇博客&#xff0c;大家新年快乐呀&#xff01;希望大家新的一年要多多进步噢&#xff01; 1.TCP/IP的四层/五层参考模型有哪些层&#xff0c;各层的特点是&#xff1f;计算机网络分层的好处是&#xff1f; TCP/IP 四层参考模型 应用层:直接为用户…

大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!

大模型Weekly 03&#xff5c;OpenAI o3发布&#xff1b;DeepSeek-V3上线即开源&#xff01;DeepSeek-V3上线即开源&#xff1b;OpenAI 发布高级推理模型 o3https://mp.weixin.qq.com/s/9qU_zzIv9ibFdJZ5cTocOw?token47960959&langzh_CN 「青稞大模型Weekly」&#xff0c;持…

【C++】B2089 数组逆序重存放

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;问题描述题目&#xff1a;数组逆序重排输入格式输出格式输入输出样例 &#x1f4af;我的代码实现**代码分析****优化建议** &#x1f4af;老师的做法与分析方法1&#xff1…

dfs复习

dfs前置知识 0小朋友崇拜圈 - 蓝桥云课 通过深搜,去找到该点指向的下一个点,然后返回所成的环的大小,保留最大的环的大小 通过添加时间戳,记录该点被遍历的时间,如果下一个点有被添加过时间戳,如果时间戳是大于等于我们的最小时间戳的(等于说明该点自成环),那么成环,…

QT---------自定义插件和库

自定义界面组件 设计和使用自定义界面组件 (以 TBattery 为例) 假设我们要创建一个自定义的电池显示组件 TBattery&#xff0c;我们可以从 QWidget 派生一个新的类&#xff1a; #include <QWidget> #include <QPainter>class TBattery : public QWidget {Q_OBJE…

物理知识1——电流

说起电流&#xff0c;应该从电荷说起&#xff0c;而说起电荷&#xff0c;应该从原子说起。 1 原子及其结构 常见的物质是由分子构成的&#xff0c;而分子又是由原子构成的&#xff0c;有的分子是由多个原子构成&#xff0c;有的分子只由一个原子构成。而原子的构成如图1所示。…

数据挖掘——支持向量机分类器

数据挖掘——支持向量机分类器 支持向量机最小间隔面推导基于软间隔的C-SVM非线性SVM与核变换常用核函数 支持向量机 根据统计学习理论&#xff0c;学习机器的实际风险由经验风险值和置信范围值两部分组成。而基于经验风险最小化准则的学习方法只强调了训练样本的经验风险最小…

Unity 对Sprite或者UI使用模板测试扣洞

新建两个材质球&#xff1a; 选择如下材质 设置如下参数&#xff1a; 扣洞图片或者扣洞UI的材质球 Sprite或者UI的材质球 新建一个单独Hole的canvas&#xff0c;将SortOrder设置为0&#xff0c;并将原UI的canvans的SortOrder设置为1 对2DSprite则需要调整下方的参数 hole的O…

【CSS in Depth 2 精译_099】17.5:基于页面滚动的动画时间线设置(全新)+ 17.6:最后一点建议 + 17.7:本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 17 章 动画】 ✔️ 17.1 关键帧17.2 3D 变换下的动画设置 17.2.1 添加动画前页面布局的构建17.2.2 为布局添加动画 17.3 动画延迟与填充模式17.4 通过动画传递意图 17.4…

刷入super镜像报错 FAILED (remote: ‘Error: Last flash failed : Volume Full‘)

目录 1.背景 2.排查流程 3.追根溯源,找到根因 1.背景 首先刷入的底包 在修复此问题的过程中发现super.img镜像刷入不进去,报错FAILED (remote: Error: Last flash failed : Volume Full),此问题一般是分区有问题导致的 2.排查流程 由于是底包的分区大小和源码中的super…

Linux实验报告12-Apache服务器的配置

目录 一&#xff1a;实验目的 二&#xff1a;实验内容 1&#xff1a;在WEB服务器上检查并安装必要软件 2&#xff1a;注册虚拟主机所要使用的域名 3&#xff1a;创建所需的目录 4&#xff1a;编辑配置文件 5&#xff1a;测试虚拟主机 一&#xff1a;实验目的 (1)了解…

WeNet:面向生产的流式和非流式端到端语音识别工具包

这篇文章介绍了WeNet&#xff0c;一个面向生产的开源端到端&#xff08;E2E&#xff09;语音识别工具包。WeNet的主要特点和贡献如下&#xff1a; 统一流式和非流式识别&#xff1a;提出了一种名为U2的两阶段框架&#xff0c;能够在单一模型中同时支持流式和非流式语音识别&…