最短路径问题(Dijkstra 算法java模板)

代码结构概览

这是一个实现 Dijkstra算法 的无向图最短路径程序,核心逻辑分为:

  1. 邻接矩阵初始化(用 0x3f3f 表示无穷大)
  2. Dijkstra算法核心流程
  3. 输入/输出处理

关键变量解析

static int N = 1010;            // 最大节点数
static int[][] g = new int[N][N]; // 邻接矩阵(存储边权)
static int[] dist = new int[N];   // 起点到各点的最短距离
static boolean[] st = new boolean[N]; // 标记节点是否已确定最短路径

算法流程详解

1. 邻接矩阵初始化
for (int i = 1; i <= n; i++) {
    Arrays.fill(g[i], 0x3f3f); // 初始化为无穷大
}

  • 0x3f3f 的作用:表示两个节点之间没有直接连边(即初始距离为无穷大)。
  • 为何选择 0x3f3f
    • 值足够大(16191),避免被实际边权覆盖。
    • 方便判断不可达情况(如 dist[n] == 0x3f3f)。
2. 处理输入边
for (int i = 0; i < m; i++) {
    int u = in.nextInt();
    int v = in.nextInt();
    int c = in.nextInt();
    g[u][v] = Math.min(g[u][v], c); // 处理重边,保留最小边权
    g[v][u] = Math.min(g[v][u], c); // 无向图双向更新
}
  • 处理重边:若存在多条相同边,保留权重最小的。
  • 无向图处理:同时更新 g[u][v] 和 g[v][u],确保双向连通性。
3. Dijkstra算法核心
初始化距离数组
Arrays.fill(dist, 0x3f3f); // 所有节点初始距离为无穷大
dist[1] = 0;               // 起点到自身距离为0
迭代寻找最短路径
for (int i = 0; i < n; i++) { // 迭代n次(每次确定一个节点的最短路径)
    int t = -1;
    // 找到未确定最短路径的节点中距离最小的
    for (int j = 1; j <= n; j++) {
        if (!st[j] && (t == -1 || dist[t] > dist[j])) {
            t = j;
        }
    }
    st[t] = true; // 标记该节点已确定最短路径

    // 通过节点t更新其他节点的距离
    for (int j = 1; j <= n; j++) {
        dist[j] = Math.min(dist[j], dist[t] + g[t][j]);
    }
}
  • 贪心策略:每次选择未访问节点中距离最小的节点 t,认为此时 dist[t] 是最终最短距离。
  • 松弛操作:通过 t 更新其他节点的距离(若经过 t 更短)。
结果判断
if (dist[n] == 0x3f3f) return -1; // 终点不可达
return dist[n];

关键问题解答

1. 为何用 0x3f3f 而非常见的 0x3f3f3f3f
  • 适用场景:假设边权较小(如 c ≤ 1000),0x3f3f(16191)足够大,不会溢出。
  • 节省空间:使用较小的值可减少内存占用(但需根据题目数据范围调整)。
2. 为何迭代 n 次?
  • Dijkstra算法要求每次确定一个节点的最短距离,共需 n 次迭代。
3. 如何处理无向图?
  • 输入时同时更新 g[u][v] 和 g[v][u],确保双向连通性。

潜在问题及优化

  1. 邻接矩阵空间浪费

    • 若节点数 n 接近 N=1010,空间复杂度为 O(N2)O(N2),可能超出内存限制。
    • 优化方案:改用邻接表存储稀疏图。
  2. 无穷大值选择

    • 若边权较大(如 c > 10000),0x3f3f 可能不足,导致错误。
    • 推荐调整:使用 0x3f3f3f3f(十进制 1061109567)。

总结

  • 代码功能:通过 Dijkstra 算法求解无向图中起点(节点1)到终点(节点n)的最短路径。
  • 核心逻辑:贪心选择最近节点 + 松弛操作更新距离。
  • 注意事项:确保无穷大值足够大,处理无向图的双向边。

实际应用中需根据题目数据范围调整 N0x3f3f 的值。

完整代码

package Lanqiao;

import java.util.Arrays;
import java.util.Scanner;

/**
 * @author zb
 * date2025/4/1 16:02
 */
public class Acwing849 {
    static int N = 1010;
    static int n, m ;
//    任意两点的距离
    static int [][]g = new int[N][N];
//    第i个点到起点的最短路径
    static int[] dist =new int[N];
//    判断某个点是否被访问过
    static boolean [] st = new boolean[N];


    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n =in.nextInt();m =in.nextInt();
        for (int i = 1; i <=n ; i++) {
            Arrays.fill(g[i],0x3f3f);
        }
        for (int i = 0; i <m ; i++) {
            int u = in.nextInt();
            int v= in.nextInt();
            int c = in.nextInt();
            g[u][v] =Math.min(g[u][v],c);
            g[v][u] =Math.min(g[v][u],c);

        }
        System.out.println(dijkstra());


        in.close();
    }
    static int dijkstra(){
        Arrays.fill(dist,0x3f3f);
        dist[1] =0;
//        迭代n次,迭代之后获取最终的结果集合
        for (int i = 0; i <n ; i++) {
            int t = -1; //代表还没有最短的点
            for (int j = 1; j <=n ; j++) {
                if(!st[j]&&(t==-1||dist[t]>dist[j])){
                  t =j ;

                }
            }
//            表示这个点被访问过
        st[t] = true;
                    for (int j = 1; j <=n ; j++) {
        //                从t点中转到j点的距离

                        dist[j] = Math.min(dist[j],dist[t]+g[t][j]);
                    }
                }
                if(dist[n]==0x3f3f)return -1;
                return  dist[n];


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值