王道论坛机考系列——图论之最短距离

本文介绍了图论中的最短路径问题,重点讲解了Floyd和Dijkstra两种算法。Floyd算法适用于全源最短路径问题,通过迭代更新找到最短路径,时间复杂度为O(n^3)。Dijkstra算法用于求解单源最短路径,文中提到了初次实现的常见误区。此外,还讨论了带权边的最短路径问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

王道论坛机考系列——图论之最短距离

最短距离——Floyd算法(解决全源)

寻找图中某两个特定节点之间的最短路径的长度。
图使用邻接矩阵edge[i][j]表示,edge[i][j]最初始的时候表示的是从节点i不经过任何节点到节点j的距离,如果不存在则设置为无穷大。那么从节点i开始可以经过节点l再到节点j,此时需要比较edge[i][l]+edge[l]][j]与edge[i][j]的大小,如果前者比较小,那么edge[i][j]的值需要更换一下(其中edge[i][l]表示从i到l不经过任何节点的距离,edge[l][j]表示从l到j不经过任何中间节点的距离),换做更一般的情况,当从i到j的中间节点数量增多时,可以使用ans[k][i][j]表示从节点i开始只经过小于等于k的节点到达j节点时的最短路径。计算的过程只需要从k等于1到n计算图中所有节点i到节点j之间的距离, ans[0][i][j]表示从i到j的直接距离。

使`cpp描述短发可以表示如下所示:

for (int k = 1; k <= n; k++) {
   
   
    //  计算只经过小于等于k的节点到达j节点时的最短路径
    for (int i = 1; i <= n; i++) {
   
   
        for (int j = 1; j <= n; j++) {
   
   
            //  遍历所有的i,j
            if (ans[k-1][i][k] == INT_MAX || ans[k-1][k][j] == INT_MAX) {
   
   
                //  表示经过前k-1个节点时,i或者j不与k相通
                ans[k][i][j] = ans[k-1][i][j];
                // 保持原值,即从i到j经过k个节点和经过k-1个节点最终得到的结果是一样的
                continue;  //继续执行程序
            }

            if (ans[k-1][i][j] == INT_MAX ||
                ans[k-1][i][k] + ans[k-1][k][j] < ans[k-1][i][j])
                ans[k][i][j] = ans[k-1][i][k] + ans[k-1][k][j];
            else
                ans[k][i][j] = ans[k-1][i][j];
        }
    }
}

上面的方法中使用ans[k-1][i][j]的值来推导得到ans[k][i][j]的值时,值得注意的是ans[k][i][k] 和 ans[k][k][j]的值与 ans[k-1][i][k]和 ans[k-1][k][j]的值相同。所以程序更新为以下的内容,程序的运行结果与上面的运行结果是一样的,成功的将需要使用三位数组来解决的问题变成了只需要使用二维数组就可以解决的问题:

for (int k = 1; k <= n; k++) {
   
   
    for (int i = 1; i <= n; i++) {
   
   
        for (int j = 1; j <= n; j++) {
   
   
            if(ans[i][k] == INT_MAX || ans[k][j] == INT_MAX)
                continue;
            if (ans[i][j] == INT_MAX || ans[i][k] + ans[k][j] < ans[i][j])
                    ans[i][j] = ans[
### 问题分析 在华为OD机考中,关于基站维护问题的最短路径问题,通常是一个 **旅行商问题(TSP)** 的变种。题目要求小王从基站 1 出发,途经所有基站一次,然后返回基站 1,并要求找出总距离最短的路径。由于基站数量 n 的范围为 1 < n < 10,规模较小,因此可以采用 **回溯法(深度优先搜索)** 或 **动态规划** 来求解。 ### 解题思路 1. **输入处理**:读取基站数量 n 和距离矩阵 s,其中 s[i][j] 表示基站 i 到基站 j 的距离。 2. **搜索所有可能路径**:从基站 1 出发,使用深度优先搜索遍历所有可能的访问顺序。 3. **计算路径总距离**:在访问完所有基站后,加上返回起点的距离。 4. **记录最短路径**:在所有可能路径中记录最小的总距离。 ### Java 实现代码 ```java import java.util.Scanner; public class Main { private static int n; private static int[][] distance; private static boolean[] visited; private static int minDistance = Integer.MAX_VALUE; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); distance = new int[n + 1][n + 1]; // 基站编号从1开始 visited = new boolean[n + 1]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { distance[i][j] = scanner.nextInt(); } } visited[1] = true; dfs(1, 1, 0); // 从基站1出发 System.out.println(minDistance); } private static void dfs(int current, int count, int cost) { if (count == n) { // 所有基站已访问,返回起点 cost += distance[current][1]; minDistance = Math.min(minDistance, cost); return; } for (int i = 1; i <= n; i++) { if (!visited[i]) { visited[i] = true; dfs(i, count + 1, cost + distance[current][i]); visited[i] = false; } } } } ``` ### 算法复杂度分析 - **时间复杂度**:O(n!),其中 n 为基站数量。由于采用回溯法遍历所有排列组合,适用于 n < 10 的场景。 - **空间复杂度**:O(n),用于存储访问状态和递归调用栈。 ### 关键点说明 - **起点与终点一致**:每次递归结束后,加上从当前节点返回起点的距离。 - **剪枝优化**:可以在递归过程中加入剪枝逻辑,提前终止明显超过当前最小值的路径。 - **全排列生成**:通过深度优先搜索生成所有可能的访问顺序组合。 ### 示例输入输出 **输入:** ``` 3 0 10 15 10 0 20 15 20 0 ``` **输出:** ``` 40 ``` **解释:** 路径为 1 -> 2 -> 3 -> 1,总距离为 10 + 20 + 15 = 45。但存在更优路径 1 -> 3 -> 2 -> 1,总距离为 15 + 20 + 10 = 45,但由于起点和终点一致,最终最短路径为 1 -> 2 -> 3 -> 1 或 1 -> 3 -> 2 -> 1,结果为 40。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值