「代码随想录算法训练营」第五十二天 | 图论 part10

news/2024/9/21 3:31:22/文章来源:https://www.cnblogs.com/frontpen/p/18393842

目录
  • Floyd算法
    • 题目:97. 小明逛公园
  • A * 算法
    • 题目:126.骑士的攻击
  • 最短路算法总结

Floyd算法

Floyd算法用于求解多源最短路问题(求多个起点到多个终点的多条最短路径)。在前面学习的dijkstra算法、Bellman算法都是求解单源最短路的问题(即只能有一个起点)。

注意:Floyd算法对边的权值正负没有要求,都可以处理。

Floyd的核心思想是动态规划

动态规划的五部曲:

  • 确定dp数组(dp table)以及下标的含义。
  • 确定递推公式。
  • dp数组如何初始化。
  • 确定遍历顺序。
  • 举例推导dp数组。

根据动态规划的五部曲来解释Floyd算法的遍历过程。

1. 确定dp数组(dp table)以及下标的含义。

把dp数组命名为grid数组,用来来存图。

grid[i][j][k] = m表示节点i到节点j中以[i...k]集合为中间节点的最短距离为m。

2. 确定递推公式。

分两种情况:

  1. 节点i到节点j的最短路径经过节点k。
  2. 节点i到节点j的最短路径不经过节点k。

对于第一种情况:grid[i][j][k] = grid[i][k][k - 1] + grid[k][j][k - 1]

对于第二种情况:grid[i][j][k] = grid[i][j][k - 1]

由于我们在求解最短路,因此对于这两种情况要取最小值:

grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1])

3. dp数组如何初始化。

grid[i][j][k] = m,表示节点i到节点j以[1...k]集合为中间节点的最短距离为m。

4. 确定遍历顺序。

从递推公式:grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1])可以看出,我们需要三个for循环,分别遍历i,j和k。而k依赖于k - 1,i和j的到并不依赖与i - 1或者j - 1等等。

其中遍历k的for循环一定是在最外面,这样才能一层一层去遍历。

暂不举例推导。

题目:97. 小明逛公园

题目链接:https://kamacoder.com/problempage.php?pid=1155
文章讲解:https://www.programmercarl.com/kamacoder/0097.小明逛公园.html
题目状态:看题解

思路:

Floyd算法

代码:

#include <iostream>
#include <vector>
#include <list>using namespace std;int main()
{int n, m, p1, p2, val;cin >> n >> m;// 因为边的最大距离是10^4vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10005)));for(int i = 0; i < m; ++i){cin >> p1 >> p2 >> val;grid[p1][p2][0] = val;grid[p2][p1][0] = val; // 注意这里是双向图}// 开始Floydfor(int k = 1; k <= n; ++k){for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j){grid[i][j][k] = min(grid[i][j][k - 1], grid[i][k][k - 1] + grid[k][j][k - 1]);}}}// 输出结果int z, start, end;cin >> z;while(z--){cin >> start >> end;if(grid[start][end][n] == 10005) cout << -1 << endl;else cout << grid[start][end][n] << endl;}
}

空间优化:

我们只需要记录grid[i][j][1]grid[i][j][0]就好,之后就是grid[i][j][1]grid[i][j][0]交替滚动。

#include <iostream>
#include <vector>
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));  // 因为边的最大距离是10^4for(int i = 0; i < m; i++){cin >> p1 >> p2 >> val;grid[p1][p2] = val;grid[p2][p1] = val; // 注意这里是双向图}// 开始 floydfor (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]);}}}// 输出结果int z, start, end;cin >> z;while (z--) {cin >> start >> end;if (grid[start][end] == 10005) cout << -1 << endl;else cout << grid[start][end] << endl;}
}

A * 算法

Astar是一种广搜的改良版。有的是Astar是dijkstra的改良版。

其实只是场景不同而已 我们在搜索最短路的时候,如果是无权图(边的权值都是1)那就用广搜,代码简洁,时间效率和dijkstra差不多(具体要取决于图的稠密)

如果是有权图(边有不同的权值),优先考虑dijkstra。

而Astar关键在于启发式函数, 也就是影响广搜或者dijkstra从容器(队列)里取元素的优先顺序。

本博客中使用BFS版本的A*算法。

启发式函数要影响的就是队列里元素的排序。

这是影响BFS搜索方向的关键。

对队列里节点进行排序,就需要给每一个节点权值,如何计算权值呢?

每个节点的权值为F,给出公式为:F = G + H

  • G:起点达到目前遍历节点的距离
  • H:目前遍历的节点到达终点的距离

起点达到目前遍历节点的距离 + 目前遍历的节点到达终点的距离就是起点到达终点的距离。

本题的图是无权网格状,在计算两点距离通常有如下三种计算方式:

  • 曼哈顿距离,计算方式: d = abs(x1-x2)+abs(y1-y2)
  • 欧氏距离(欧拉距离) ,计算方式:d = sqrt( (x1-x2)^2 + (y1-y2)^2 )
  • 切比雪夫距离,计算方式:d = max(abs(x1 - x2), abs(y1 - y2))

x1, x2 为起点坐标,y1, y2 为终点坐标 ,abs 为求绝对值,sqrt 为求开根号,

选择哪一种距离计算方式 也会导致 A * 算法的结果不同。

动态模拟地址:https://kamacoder.com/tools/knight.html

题目:126.骑士的攻击

题目链接:https://kamacoder.com/problempage.php?pid=1203
文章讲解:https://www.programmercarl.com/kamacoder/0126.骑士的攻击astar.html
题目状态:看题解

思路:

A*算法

代码:

#include <iostream>
#include <queue>
#include <string.h>using namespace std;int moves[1001][1001];
int dir[8][2] = {-2, -1, -2, 1, -1, 2, 1, 2, 2, 1, 2, -1, 1, -2, -1, -2};
int b1, b2;// F = G + H
// G = 从起点到该节点路径消耗
// H = 该节点到终点的预估消耗struct Knight
{int x, y;int g, h, f;// 重载运算符,从小到大排序bool operator<(const Knight &k) const{return k.f < f;}
};priority_queue<Knight> que;// 欧拉距离
int Heuristic(const Knight &k)
{// 统一不开根号,这样可以提高精度return (k.x - b1) * (k.x - b1) + (k.y - b2) * (k.y - b2);
}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){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;que.push(next);}}}
}int main()
{int n, a1, a2;cin >> n;while(n--){cin >> a1 >> a2 >> b1 >> b2;memset(moves, 0, sizeof(moves));Knight start;start.x = a1;start.y = a2;start.g = 0;start.h = Heuristic(start);start.f = start.g + start.h;astar(start);while(!que.empty()) que.pop(); // 队列清空cout << moves[b1][b2] << endl;}return 0;
}

最短路算法总结

image

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

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

相关文章

定义一个正则表达式,使用finditer从表达式内取值后存储到列表中

演示代码:responce = requests.get(url = url_web,headers=head) url_obj = re.compile(r<a class="media-content" target="_blank" href="(?P<url>.*?)" title=".*?" ,re.S) list_url = url_obj.finditer(responce.tex…

大模型隐私泄露攻击技巧分析与复现

大型语言模型,尤其是像ChatGPT这样的模型,尽管在自然语言处理领域展现了强大的能力,但也伴随着隐私泄露的潜在风险。在模型的训练过程中,可能会接触到大量的用户数据,其中包括敏感的个人信息,进而带来隐私泄露的可能性。前言 大型语言模型,尤其是像ChatGPT这样的模型,尽…

反光衣自动识别检测系统

反光衣自动识别检测系统检测预警信息仪仗于完整的Ai智能分析平台,包含视频监管、视频采集、预测分析预警信息、可视化管理、时间监管、等模块,反光衣自动识别检测系统可以完成业务流程数据信息的数据共享,产生完善的安全生产管理体系。反光衣自动识别检测系统以健全设备的基…

深入剖析 PCI 转 CPCI 载板转接卡:连接不同架构的桥梁

在计算机技术不断发展的进程中,硬件接口的多样性和演进促使了各种转接卡的出现,以满足不同接口标准之间的连接和通信需求。其中,PCI 转 CPCI 载板转接卡作为一种关键的转接设备,在实现 PCI(Peripheral Component Interconnect)接口与 CPCI(CompactPCI)接口之间的转换方…

VMware Workstation 17.5.2 Pro for Linux 更新 OEM BIOS 2.7 支持 Windows Server 2025

VMware Workstation 17.5.2 Pro for Linux 更新 OEM BIOS 2.7 支持 Windows Server 2025VMware Workstation 17.5.2 Pro for Linux 更新 OEM BIOS 2.7 支持 Windows Server 2025 VMware Workstation 17.5.2 Pro macOS Unlocker & OEM BIOS 2.7 for Linux 在 Linux 上运行 m…

VMware Workstation 17.5.2 Pro for Windows 更新 OEM BIOS 2.7 支持 Windows Server 2025

VMware Workstation 17.5.2 Pro for Windows 更新 OEM BIOS 2.7 支持 Windows Server 2025VMware Workstation 17.5.2 Pro for Windows 更新 OEM BIOS 2.7 支持 Windows Server 2025 VMware Workstation 17.5.2 Pro macOS Unlocker & OEM BIOS 2.7 for Windows 在 Windows …

安全帽自动识别软件

安全帽自动识别软件提升现场管控效率、降低控制成本、提升企业生产管理规范、降低生产制造安全事故和产品质量安全隐患等作用。安全帽自动识别软件在施工工地十分关键,有时候乃至变成一顶救人的防护措施,所以大家需要依照规定恰当佩戴相对应色彩的安全帽,以减少很多不必要的…

1. 初识算法

1. 什么是算法 定义 : 在数学和计算机科学领域,算法是一系列有限的严谨指令,通常用于解决一类特定问题或执行计算In mathematics and computer science, an algorithm (/ˈlɡərɪəm/) is a finite sequence of rigorous instructions, typically used to solve a class o…

工地安全帽视频智能识别监测系统

工地安全帽视频智能识别监测系统根据安装在现场施工工地的各处各品牌的监控摄像头,组建智能监管和预警系统,工地安全帽视频智能识别监测系统开展面部识别、个人行为识别和安全帽识别,合理填补智能现场监管中传统式方法和技术的缺点,真真正正完成预警信息、正常的检验、规范…

探索 PCI 转 PMC 载板转接卡:连接不同接口的桥梁

在计算机硬件领域,各种接口和总线标准不断演进,以满足日益增长的性能和功能需求。在这个过程中,不同接口之间的转换设备应运而生,其中 PCI 转 PMC 载板转接卡就是一种重要的连接解决方案。 PCI 转 PMC 载板转接卡,顾名思义,是一种用于将计算机的 PCI(Peripheral Compone…

keycloak~scope客户端模板的使用

scope为何物? scope在oauth2中表示授权的范围,另外也可以理解为,根据认证时scope的参数,在构建jwt时,返回更多的信息;比如在keycloak中,你的可选scope(optional scope)中添加了address这个模板,当你通过/auth/realms/{realmId}/protocol/openid-connect/token进行认证时…