• Dijkstra算法的java实现


    Dijkstra算法主要是针对单源的,用于求一个点到其他各点的最短路径。其中点与点之间的边的权重不存在负值的情况。

    先看下图(手上没有好的画图工具,先将就看看):

    设以点0位源点,求0到其他各点的最短路径。

    首先我们用一个二维矩阵来表示各点之间的距离(这个矩阵太丑了):

    这个二维矩阵表示的只是各点之间的距离。所以我们为了能够更直观的看出源点到其他各点的距离,可以用一个一维数组去记录源点到其他各点的距离:

    其中的dis[i]代表源点到点i的直接可达距离。

    准备工作完成之后,我们可以进行求解了:

    首先找到距离源点最近的点,通过dis这个数组可以得到,1号顶点是距离源点最近的点。当选择了1号顶点之后,那么dis[1]的值就完全确定了,原因是这个图的所有边的值都是正数,而源点到1号顶点的距离是最近的,所以源点到1号顶点的距离不可能通过第三个顶点中转,使得源点到1号的距离进一步缩短。

    在选择了1号顶点之后,可以看1号的出边有哪些。通过图可以看到,1号的出边有1→2以及1→3两条边。我们首先讨论一下1→2这条边。现在,我们可以比较,究竟是0→2的距离短还是0→1→2的距离短,其中0→1→2的距离可以通过dis[1]+dis[1][2]来计算。可以发现,0→1→2的距离为1+9=10,而0→2的距离为12,所以从源点到2号顶点的暂时的最近距离为10,故我们可以更新dis数组:

    再来讨论0→3的距离:

    在dis数组中可以发现,源点到3号顶点是没有直接路径可以到达的,但是可以通过0→1→3这条路径抵达,那么0→3目前的最短距离即为dis[1]+map[1][3]=4,所以我们可以再次更新dis数组:

     同理,源点到其他各点的距离,可以通过上面的步骤来求得,最终的结果如下:

    现在,我们可以总结一下Dijkstra算法的思想了:每次找到距离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其他各点的最短路径。基本步骤如下:

    ①首先把所有的顶点分为两个部分:已找到最短路径的顶点集合P和未找到最短路径的顶点集合Q。最开始进行时,P中只有源点这么一个元素。在这里,我们可以用一个标记数组visited来记录哪些点在集合P中;

    ②设一个数组dis来存储源点到其余各点之间的距离,那么dis[0]=0。如果存在有源点可以直接到达的顶点i,那么把dis[i]设为map[0][i],其余的各点设为无穷大;

    ③在Q中选择一个距离源点最近的顶点u(dis[u]最小),加入到集合P中。同时以u为中心点,向周围扩展,考察所有以u为起点的边,并且进行松弛操作。需要的话,可以及时更新dis数组中的值。

    ④重读第③步,当Q为空时,代表源点到其他各点的最短路径均已找到,算法结束。

    实现代码如下:

    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int N = sc.nextInt();  //顶点的个数
            int M = sc.nextInt();  //边的个数
            int max = Integer.MAX_VALUE;  //无穷大,设为不可达
            int[][] map = new int[N][N]; //存储各顶点之间的距离
            for (int i = 0; i < N; i++){
                for (int j = 0; j < N; j++){
                    if (i == j)
                        map[i][j] = 0;
                    else
                        map[i][j] = max;
                }
            }
            //输入各点之间的距离
            for (int k = 0; k < M; k++){
                int a = sc.nextInt(); //起点
                int b = sc.nextInt(); //终点
                int c = sc.nextInt(); //距离
                map[a][b] = c;
            }
            int[] dis = new int[N]; //源点到各点的距离,源点设为0
            for (int i = 0; i < N; i++)
                dis[i] = map[0][i];
            boolean[] visited = new boolean[N];
            visited[0] = true;
            //Dijkstra
            for (int i = 0; i < N; i++){
                int min = max;
                int idx = 0;
                //找到距离源点最近的点
                for (int j = 0; j < N; j++){
                    if (!visited[j] && dis[j] < min){
                        min = dis[j];
                        idx = j;
                    }
                }
                visited[idx] = true;
                //扩展
                for (int k = 0; k < N; k++){
                    if (map[idx][k] < max){
                        if (map[idx][k] + dis[idx] < dis[k])
                            dis[k] = map[idx][k] + dis[idx];
                    }
                }
            }
            for (int l = 0; l < N; l++){
                System.out.print(dis[l] + " ");
            }
        }
    }

    输入数据及输出结果:

     

  • 相关阅读:
    PDO 数据访问抽象层
    注册审核、批量删除
    分页查询
    会话用法
    封装成类
    多条件查询(复选框条件)
    IP子网划分
    redhat 用yum安装的apache、mysql一般默认安装在哪个目录下?
    nslookup
    linux 设置时间
  • 原文地址:https://www.cnblogs.com/WakingShaw/p/14468523.html
Copyright © 2020-2023  润新知