97. 小明逛公园
Floyd 算法
Floyd-Warshall算法是一种用于求解图中所有节点对之间最短路径的经典算法。它的时间复杂度为O(n^3),适用于节点数量不多(通常不超过几百个)的密集图。该算法不仅能处理带权有向图,还能处理带权无向图。
核心思想:动态规划
Floyd-Warshall算法通过引入中间节点的方式,逐步更新节点对之间的最短路径。先遍历中间节点k的原因是为了确保每次更新节点对(i, j)的路径时,都已经考虑过通过所有之前的节点(从1到k-1)作为中间节点的可能性
算法步骤:
1. 初始化:将每个节点对之间的初始距离存储在一个二维数组grid中。如果存在直接边,则将grid[i][j]设为对应的边权重;如果不存在,则设为一个大值(通常表示无穷大),自身到自身的距离设为0。
2. 动态规划:
• 通过引入中间节点k逐步更新最短路径。
• 三重循环遍历每个节点对,并检查通过每个中间节点k是否能找到更短的路径。
• 具体地,检查dist[i][j]是否大于dist[i][k] + dist[k][j],如果是则更新dist[i][j]为后者。
3. 输出结果:完成所有更新后,dist[i][j]中存储的就是节点i到节点j的最短路径长度。
代码实现:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取节点数n和边数m
int n = scanner.nextInt();
int m = scanner.nextInt();
// 初始化grid数组,表示节点间的最短路径
int[][] grid = new int[n + 1][n + 1];
// 将grid数组中的所有值初始化为较大值(表示无穷大)
for (int[] ints : grid) {
Arrays.fill(ints, 10005);
}
// 自身到自身的距离设为0
for (int i = 1; i <= n; i++) {
grid[i][i] = 0;
}
// 读取边的信息并更新grid数组
for (int i = 0; i < m; i++) {
int s = scanner.nextInt(); // 起点
int t = scanner.nextInt(); // 终点
int val = scanner.nextInt(); // 边的权重
grid[s][t] = val; // 初始时刻的最短路径
grid[t][s] = val; // 无向图,双向更新
}
// 读取查询的计划数
int q = scanner.nextInt();
int[][] plans = new int[q][2];
// 读取查询计划的起点和终点
for (int i = 0; i < q; i++) {
plans[i][0] = scanner.nextInt();
plans[i][1] = scanner.nextInt();
}
// 使用Floyd-Warshall算法进行多阶段动态规划求解最短路径
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]);
}
}
}
// 输出每个查询计划的结果
for (int[] plan : plans) {
int start = plan[0];
int end = plan[1];
int res = grid[start][end];
// 如果距离还是初始的较大值,表示两点之间无路径
System.out.println(res == 10005 ? -1 : res);
}
}
127. 骑士的攻击
A * 算法
A*算法是一种用于图搜索的启发式算法,广泛应用于路径规划和导航等领域。它结合了Dijkstra算法的最短路径搜索和启发式搜索策略,能够高效地找到从起点到终点的最短路径。
A*算法的基本思路:
A*算法通过以下三个值来进行路径搜索:
1. G值:从起点到当前节点的实际消耗。
2. H值:从当前节点到终点的预估消耗(启发式函数)。
3. F值:F = G + H,表示经过当前节点的总消耗。
算法步骤
1. 初始化:
• 将起点加入到开放列表(open list)中,并初始化其G、H和F值。
• 开放列表用于存储待检查的节点,关闭列表(closed list)用于存储已检查的节点。
2. 选择当前节点:
• 从开放列表中选择F值最小的节点作为当前节点。如果当前节点是终点,则搜索结束。
• 否则,将当前节点从开放列表移除并加入关闭列表。
3. 处理相邻节点:
• 对于当前节点的每个相邻节点,计算其G、H和F值:
• 如果相邻节点在关闭列表中,则跳过。
• 如果相邻节点不在开放列表中,则将其加入开放列表,并设置其父节点为当前节点。
• 如果相邻节点已经在开放列表中,但通过当前节点到达相邻节点的G值更小,则更新相邻节点的G值和父节点。
4. 重复步骤2和步骤3,直到找到终点或开放列表为空(表示无解)。
启发式函数
启发式函数H的选择非常重要,直接影响A*算法的性能。常用的启发式函数有:
• 曼哈顿距离:适用于棋盘格上的移动,不允许对角线移动。
• 欧几里得距离:适用于允许任意方向移动的情况。
• 切比雪夫距离:适用于允许八方向(包括对角线)移动的情况。
最短路算法总结
如何选用?
高要求:
这个过程中考虑点还是边看是稠密图还是稀疏图
低要求: 会个Floyd和朴素版本Bellman-Ford以及变种即可
- 多源就用Floyd-Warshall算法
- 单源就用(朴素版本Bellman-Ford算法 + 负权回路检测) 版本
- 2.1 有限就用有限节点最短路径版本(朴素版本Bellman-Ford算法 + 负权回路检测 + 有限节点)版本