【代码随想录训练营第42期 Day61打卡 - 图论Part11 - Floyd 算法与A * 算法

目录

一、Floyd算法与A * 算法

1、Floyd算法

思想

伪代码

2、 A * 算法

思想

伪代码

二、经典题目

题目一:卡码网 97. 小明逛公园

题目链接

题解:Floyd 算法

题目二:卡码网 127. 骑士的攻击

题目链接

 题解:A * 算法(A-Star)

三、小结


一、Floyd算法与A * 算法

1、Floyd算法

思想

Floyd算法的基本思想是逐步迭代地考虑图中的所有顶点,并更新任意两点之间的最短路径长度。在每一步迭代中,算法检查所有顶点对(i,j),并通过当前考虑的顶点k,看是否能够找到一条从i到j的更短路径。具有能够找到图中任意两点间的最短路径的优势,适合解决多源最短路,即求多个起点到多个终点的多条最短路径

Floyd算法核心思想是动态规划

伪代码
function floydWarshall(weights, V):let dist be a V x V arrayfor i from 0 to V-1:for j from 0 to V-1:if i == j:dist[i][j] = 0else if there is an edge from i to j:dist[i][j] = weight of the edge from i to jelse:dist[i][j] = INFINITYfor k from 0 to V-1:for i from 0 to V-1:for j from 0 to V-1:if dist[i][k] + dist[k][j] < dist[i][j]:dist[i][j] = dist[i][k] + dist[k][j]return dist

2、 A * 算法

入门建议观看视频:【A*寻路算法详解 #A星 #启发式搜索】

思想

A算法(A-Star算法)是一种在图形平面上,有多个节点的路径中,寻找一条从起点到终点的最短路径的算法。它的设计思想主要结合了实际代价和启发式估计,以高效地搜索图形中的最优路径。

核心思想是将启发式搜索和最佳优先搜索结合起来,以寻找从起始点到目标点的最短路径。

伪代码
function A*(start, goal)open_list = priority_queue() // 优先队列,按f值排序start.g = 0start.h = heuristic(start, goal)start.f = start.g + start.hstart.parent = nullopen_list.add(start)while not open_list.is_empty()current = open_list.pop() // 取出f值最小的节点if current == goalreturn reconstruct_path(current)closed_list.add(current) // 将当前节点加入封闭列表for neighbor in neighbors(current)if neighbor in closed_listcontinuetentative_g = current.g + distance(current, neighbor)if neighbor not in open_list or tentative_g < neighbor.gneighbor.parent = currentneighbor.g = tentative_gneighbor.h = heuristic(neighbor, goal)neighbor.f = neighbor.g + neighbor.hif neighbor not in open_listopen_list.add(neighbor)return null // 没有找到路径function reconstruct_path(node)path = []while node is not nullpath.prepend(node)node = node.parentreturn path.reverse() // 反转路径以从起点到终点function heuristic(node, goal)// 返回从node到goal的启发式估计值
end functionfunction neighbors(node)// 返回node的邻居节点列表
end functionfunction distance(node1, node2)// 返回从node1到node2的实际距离
end function

二、经典题目

题目一:卡码网 97. 小明逛公园

题目链接

97. 小明逛公园 (kamacoder.com)

题目描述

小明喜欢去公园散步,公园内布置了许多的景点,相互之间通过小路连接,小明希望在观看景点的同时,能够节省体力,走最短的路径。 

给定一个公园景点图,图中有 N 个景点(编号为 1 到 N),以及 M 条双向道路连接着这些景点。每条道路上行走的距离都是已知的。

小明有 Q 个观景计划,每个计划都有一个起点 start 和一个终点 end,表示他想从景点 start 前往景点 end。由于小明希望节省体力,他想知道每个观景计划中从起点到终点的最短路径长度。 请你帮助小明计算出每个观景计划的最短路径长度。

输入描述

第一行包含两个整数 N, M, 分别表示景点的数量和道路的数量。 

接下来的 M 行,每行包含三个整数 u, v, w,表示景点 u 和景点 v 之间有一条长度为 w 的双向道路。 

接下里的一行包含一个整数 Q,表示观景计划的数量。 

接下来的 Q 行,每行包含两个整数 start, end,表示一个观景计划的起点和终点。

输出描述

对于每个观景计划,输出一行表示从起点到终点的最短路径长度。如果两个景点之间不存在路径,则输出 -1。

输入示例

7 3
2 3 4
3 6 6
4 7 8
2
2 3
3 4

输出示例

4
-1

提示信息

从 2 到 3 的路径长度为 4,3 到 4 之间并没有道路。

1 <= N, M, Q <= 1000.

题解:Floyd 算法

关键在于Floyd算法的实现,即:

使用三重循环来实现Floyd算法:

外层循环变量 k 代表中间节点,内两层循环变量 i 和 j 分别代表起点和终点。

在每一轮循环中,检查通过中间节点 k 从 i 到 j 的路径是否比当前已知的路径更短,如果是,则更新 grid[i][j]。

代码实现:

 for (int k = 1; k <= n; k++) // k代表中间节点{for (int i = 1; i <= n; i++) // i代表起点{for (int j = 1; j <= n; j++) // j代表终点{grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]); // 更新i到j的最短路径,如果通过k的路径更短,则更新}}}

完整代码如下:

#include <bits/stdc++.h>
using namespace std;int main()
{int n, m, p1, p2, val;cin >> n >> m;vector<vector<int>> grid(n + 1, vector<int>(n + 1, 10005)); // 创建一个二维向量grid来存储图的邻接矩阵,因为边的最大距离为10**4// 读取m条边的信息,并更新邻接矩阵for (int i = 0; i < m; i++){cin >> p1 >> p2 >> val;grid[p1][p2] = val;grid[p2][p1] = val; // 注意这里是双向图:需要考虑两个方向}// 开始 floyd 算法for (int k = 1; k <= n; k++) // k代表中间节点{for (int i = 1; i <= n; i++) // i代表起点{for (int j = 1; j <= n; j++) // j代表终点{grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]); // 更新i到j的最短路径,如果通过k的路径更短,则更新}}}// 输出结果int Q, start, end;cin >> Q;while (Q--){cin >> start >> end;if (grid[start][end] == 10005) // 如果最短路径长度仍然是初始值,表示没有路径cout << -1 << endl;elsecout << grid[start][end] << endl;}return 0;
}

题目二:卡码网 127. 骑士的攻击

题目链接

127. 骑士的攻击 (kamacoder.com)

题目描述

在象棋中,马和象的移动规则分别是“马走日”和“象走田”。现给定骑士的起始坐标和目标坐标,要求根据骑士的移动规则,计算从起点到达目标点所需的最短步数。

棋盘大小 1000 x 1000(棋盘的 x 和 y 坐标均在 [1, 1000] 区间内,包含边界)

输入描述

第一行包含一个整数 n,表示测试用例的数量,1 <= n <= 100。

接下来的 n 行,每行包含四个整数 a1, a2, b1, b2,分别表示骑士的起始位置 (a1, a2) 和目标位置 (b1, b2)。

输出描述

输出共 n 行,每行输出一个整数,表示骑士从起点到目标点的最短路径长度。

输入示例

6
5 2 5 4
1 1 2 2
1 1 8 8
1 1 8 7
2 1 3 3
4 6 4 6

输出示例

2
4
6
5
1
0

提示信息

骑士移动规则如图,红色是起始位置,黄色是骑士可以走的地方。

 题解:A * 算法(A-Star)

关键在于A*算法实现的部分:

在astar函数中,使用优先队列来存储当前的Knight对象;

循环直到优先队列为空,即所有可能的路径都被检查过;

在每次循环中,从优先队列中取出F值最小的Knight对象,并检查是否到达目标位置;

如果未到达目标位置,则遍历8个可能的方向,计算下一个位置的坐标,并检查是否越界或已经被访问过;

如果下一个位置合法且未被访问过,则更新路径消耗,计算F值,并将其加入优先队列;

当到达目标位置时,循环结束。

实现代码:

void astar(const Knight &k)
{Knight cur, next;que.push(k);while (!que.empty()){cur = que.top();que.pop();if (cur.x == b1 && cur.y == b2)break;for (int i = 0; i < 8; i++) // 遍历骑士的8个可能移动方向{// 得到下一个位置的坐标next.x = cur.x + dir[i][0];next.y = cur.y + dir[i][1];if (next.x < 1 || next.x > 1000 || next.y < 1 || next.y > 1000) // 如果下一个位置越界,则跳过continue;if (!moves[next.x][next.y]) // 如果下一个位置没有被访问过{moves[next.x][next.y] = moves[cur.x][cur.y] + 1; // 更新下一个位置的路径消耗// 开始计算Fnext.g = cur.g + 5;       // 统一不开根号,这样可以提高精度,马走日,1 * 1 + 2 * 2 = 5next.h = Heuristic(next); // 计算当前节点到终点的预估消耗next.f = next.g + next.h; // 计算F值que.push(next);           // 将下一个位置的Knight对象加入优先队列}}}
}

 完整代码实现:

#include <bits/stdc++.h>
using namespace std;int moves[1001][1001];                                              // 定义一个二维数组moves,用于存储骑士从起点到当前位置的移动步数
int dir[8][2] = {-2, -1, -2, 1, -1, 2, 1, 2, 2, 1, 2, -1, 1, -2, -1, -2}; // 定义一个方向数组dir,用于存储骑士可能的移动方向
int b1, b2;struct Knight // 定义一个结构体Knight,用于存储骑士的当前位置和路径消耗等信息
{int x, y;int g, h, f;bool operator<(const Knight &k) const // 重载运算符,用于优先队列的排序{return k.f < f; // 从小到大排序}
};priority_queue<Knight> que; // 定义一个优先队列que,用于存储Knight对象,并按照f值排序int Heuristic(const Knight &k) // 欧拉距离
{return (k.x - b1) * (k.x - b1) + (k.y - b2) * (k.y - b2); // 统一不开根号,这样可以提高精度
}
// 执行A*算法:参数k是当前的Knight对象
void astar(const Knight &k)
{Knight cur, next;que.push(k);while (!que.empty()){cur = que.top();que.pop();if (cur.x == b1 && cur.y == b2)break;for (int i = 0; i < 8; i++) // 遍历骑士的8个可能移动方向{// 得到下一个位置的坐标next.x = cur.x + dir[i][0];next.y = cur.y + dir[i][1];if (next.x < 1 || next.x > 1000 || next.y < 1 || next.y > 1000) // 如果下一个位置越界,则跳过continue;if (!moves[next.x][next.y]) // 如果下一个位置没有被访问过{moves[next.x][next.y] = moves[cur.x][cur.y] + 1; // 更新下一个位置的路径消耗// 开始计算Fnext.g = cur.g + 5;       // 统一不开根号,这样可以提高精度,马走日,1 * 1 + 2 * 2 = 5next.h = Heuristic(next); // 计算当前节点到终点的预估消耗next.f = next.g + next.h; // 计算F值que.push(next);           // 将下一个位置的Knight对象加入优先队列}}}
}int main()
{int n, a1, a2;cin >> n;while (n--){cin >> a1 >> a2 >> b1 >> b2;memset(moves, 0, sizeof(moves)); // 每次循环都初始化moves数组为0,确保每个骑士问题都有独立的路径记录// 定义起点Knight对象start// F = G + H// G = 从起点到该节点路径消耗// H = 该节点到终点的预估消耗Knight start;start.x = a1;start.y = a2;start.g = 0;start.h = Heuristic(start);start.f = start.g + start.h;// 执行A*算法,以起点Knight对象start为起点astar(start);// 执行A*算法后,清空优先队列que,以便下一次循环使用while (!que.empty())que.pop();cout << moves[b1][b2] << endl; // 输出本次从起点到目标点的路径消耗,即moves[b1][b2]}return 0;
}

三、小结

这算是图论最后的内容了,难度很大,个人感觉只是理解了大概意思,却难以代码实现,后边二刷的时候会强化理解,继续加油!

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

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

相关文章

啤酒:从饮品到文化的演变

在人类饮品的长河中&#xff0c;啤酒以其不同的魅力走过了一段漫长的历史旅程。它不仅仅是一种简单的饮品&#xff0c;更是一种文化的象征&#xff0c;一种生活的态度。今天&#xff0c;我们将一起追溯啤酒从单一的饮品到丰富文化的演变过程&#xff0c;并感受Fendi Club精酿啤…

LeetCode讲解篇之238. 除自身以外数组的乘积

文章目录 题目描述题解思路题解代码 题目描述 题解思路 对于该题&#xff0c;我们可以先使用一个循环记录所有非零元素的乘积结果和非零元素的个数 如果非零元素个数为0&#xff0c;则非零元素的乘积除以数组对应位置的数字就是除自身以外的数组的乘积如果非零元素个数为1&am…

达梦数据库配置SSL通信加密

相关概念&#xff1a; SSL通过在发送方和接收方之间建立加密通道&#xff0c;确保数据在传输过程中的安全性和完整性。 SSL的关键特点 加密通信&#xff1a;SSL使用对称和非对称加密技术来加密数据&#xff0c;确保数据在传输过程中不被窃听或篡改。 身份验证&#xff1a;通…

centos7 更新 yum源 为 阿里云 LTS

centos7 更新 yum源 为 阿里云 按照下面的 步骤 1,2&#xff0c;3,4 来一遍 参考文档 CentOS yum源设置为国内aliyun yum源 https://developer.aliyun.com/article/1523301?spm5176.26934562.main.2.16c938e4ys9prQ CentOS 镜像 https://developer.aliyun.com/mirror/cent…

理解C语言之深入理解指针(三)

目录 1. 字符指针变量 2. 数组指针变量 2.1 数组指针变量是什么&#xff1f; 2.2 数组指针变量怎么初始化 3. ⼆维数组传参的本质 4. 函数指针变量 4.1 函数指针变量的创建 4.2 函数指针变量的使⽤ 4.3 两段有趣的代码 4.3.1 typedef 关键字 5. 函数指针数组 6. 转移…

构建高可用和高防御力的云服务架构第五部分:PolarDB(5/5)

引言 云计算与数据库服务 云计算作为一种革命性的技术&#xff0c;已经深刻改变了信息技术行业的面貌。它通过提供按需分配的计算资源&#xff0c;使得数据存储、处理和分析变得更加灵活和高效。在云计算的众多服务中&#xff0c;数据库服务扮演着核心角色。数据库服务不仅负…

PHP之 实现https ssl证书到期提醒,通过企微发送消息

参考文章 https://blog.51cto.com/17099933344/1935194 https://blog.csdn.net/m0_37346206/article/details/127333463 https://www.cnblogs.com/tk-bolg/p/18108106 使用的企微接口 https://qyapi.weixin.qq.com/cgi-bin/message/send 查询 ssl证书到期时间 // ssl证书即将…

Linux·进程概念(上)

1.操作系统 任何计算机系统都包含一个基本的程序合集&#xff0c;称为操作系统(Operator System)。笼统的理解&#xff0c;操作系统包括&#xff1a; 内核(进程管理&#xff0c;内存管理&#xff0c;文件管理&#xff0c;驱动管理) 其他程序(函数库&#xff0c;shell程序) OS的…

SpringCloudEureka简介

背景 SpringCloudEureka是基于NetfliEureka做了二次封装&#xff0c;负责微服务架构的服务治理功能。 SpringCloud通过为Eureka增加SpringBoot风格的自动化配置&#xff0c;只需要简单的引入依赖和注解配置&#xff0c;就能让SpringBoot构建的微服务应用轻松和Eureka服务治理体…

uniapp实现展示1个或多个文字标签,可点击切换选中、不选中的状态

前言 uni-tag是uni-app框架提供的一个标签组件&#xff0c;用于展示标签或者标记某个元素。它可以在视图中用来显示一组标签&#xff0c;并且支持自定义样式和事件。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 uni-notice-bar组件具有以下特点&…

cefsharp新版本OnBeforeResourceLoad 禁止http自动跳转https显示404错误解决办法 含代码

一、问题 因项目需要,域名没有ssl证书,结果http访问时被强制定向到https前缀,结果会显示404 测试版本cefsharp126.x (x64) 框架 CefSharp.WinForms.NETCore 二、代码(核心代码) 如果请求url是http,且目标是https时,则阻止请求 //判断请求变化 if (url.StartsWith(<…

LInux操作系统安装Jenkins

1、什么是Jenkins Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。 2、Jenkins的作用 持续的软件版本发布/测试项目。 监控…

B-6 meshshader实现,利用vulkan和obj模型

B-6 2024/9/26 MeshShader实现 Vulkanobj模型 经过多次尝试终于实现了meshshader环境&#xff1a;vulkan、fastobj(阅读obj模型)、meshoptimizer(网格分组)放两张截图吧。龙有261w个顶点&#xff0c;87w个三角形。 meshshader流程说明 获取模型的网格数据&#xff0c;也就是顶…

Cpp内存管理(7)

文章目录 前言一、C/C内存区域划分二、C/C动态内存管理C语言动态内存管理C动态内存管理对于内置类型对于自定义类型 三、new和delete的底层实现四、new和delete的实现原理五、定位new六、malloc/free和new/delete的区别总结 前言 软件开发过程中&#xff0c;内存管理的重要性不…

关于 mybatis-plus-boot-starter 与 mybatis-spring-boot-starter 的错误

不是知道你是否 出现过这样的错误 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): 经过各种度娘&#xff0c;无非就是让你检查三种情况 情况一&#xff1a;mapper.xml没有按照传统的maven架构进行放置 情况二&#xff1a;mybatis的配置信…

c++ day06

类的栈 实现 #include <iostream>using namespace std;class Stack { private:static const size_t MAX 100; // 定义固定容量int data[MAX]; // 存储栈元素的数组size_t len; // 当前栈的大小public:// 构造函数Stack() : len…

【Python从入门到进阶】65、Pandas如何批量拆分与合并Excel文件

接上篇《64、Pandas如何实现数据的Concat合并》 上一篇我们学习了Pandas如何实现数据的Concat合并&#xff0c;本篇我们来继续学习Pandas如何批量拆分与合并Excel文件。 一、引言 在当今数据驱动的时代&#xff0c;Excel文件作为数据处理和分析的基石&#xff0c;扮演着不可或…

Selenium4.0实现自动搜索功能

01.Selenium4.0实现搜索功能 1.安装Selenium及查看Selenium版本 pip install selenium pip show seleniumfrom selenium import webdriver from chromedriver_py import binary_path import time from selenium.webdriver.common.by import By from selenium.webdriver.commo…

(补充)3DMAX初级小白班第三课:创建物体+物体材质编辑

1.可以点这里来改变材质颜色&#xff08;但是通过材质编辑器给了材质以后就只能在这里改线框颜色&#xff09;。但一般就是用灰色材质和黑色线框 2.材质编辑器快捷键为m 右键可更改个数&#xff0c;最多24个 将材质指定选定对象 如何把材质编辑器面板改成旧版 按f10 改成扫描…

《微信小程序实战(3) · 推广海报制作》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…