HengYk Blog

个人站

具有浪漫主义情调的理想主义务实青年


最短路径问题解决方案

最短路径SPF问题解决方案
  • 深度优先遍历DFS

        /**
         * 深度优先遍历Depth-First Transverse
         *
         * @param cur
         * @param dis
         * @param n
         * @param dest
         * @param edges
         * @param visited
         */
        public static void dfs(int cur, int dis, int n, int dest, int[][] edges, int[] visited) {
    
            // 如果当前的dis(当前已经走过的路程)已经大于min,则没有必要再走下去
            if (dis > min) {
                return;
            }
    
            // 判断是否到达了目标城市
            if (cur == dest) {
                if (dis < min) {
                    min = dis;
                }
                return;
            }
    
            // 从0号城市到n-1号城市逐个尝试
            for (int j = 0; j < n; j++) {
    
                if (visited[j] == 0 && edges[cur][j] != Integer.MAX_VALUE) {
                    visited[j] = 1;
                    dfs(j, dis + edges[cur][j], n, dest, edges, visited);
                    visited[j] = 0;
                }
            }
    
        }
    
  • 广度优先遍历BFS

        static class Note {
            int x; // 城市编号
            int s; // 记录从源点到其他城市的距离
    
            public Note() {
    
            }
    
            public Note(int x, int s) {
                this.x = x;
                this.s = s;
            }
    
            public int getX() {
                return x;
            }
    
            public void setX(int x) {
                this.x = x;
            }
    
            public int getS() {
                return s;
            }
    
            public void setS(int s) {
                this.s = s;
            }
        }
    
        /**
         * 广度优先遍历Breath-First Transverse
         *
         * @param n
         * @param visited
         * @param edges
         * @param start 源点
         * @param end 目标点
         */
        public static void bfs(int n, int[] visited, int[][] edges, int start, int end) {
    
            Note[] que = new Note[n];
    
            // 队列的初始化
            for (int i = 0; i < n; i ++) {
                que[i] = new Note();
            }
    
            int head = 0;
            int tail = 0;
    
            // 从start号城市出发,将start号城市加入队列
            que[tail].setX(start);
            que[tail].setS(0);
            tail++;
            visited[start] = 1;
    
            // 当队列不为空的时候循环
            while (head < tail) {
                int cur = que[head].getX();
                for (int j = 0; j < n; j++) {
    
                    // 判断当前城市cur到目标城市j是否可达
                    if (edges[cur][j] != Integer.MAX_VALUE && visited[j] == 0) {
    
                        // que[tail] = new Note(j, que[head].s + edges[cur][j]);
                        que[tail].setX(j);
                        que[tail].setS(que[head].getS() + edges[cur][j]);
                        tail++;
    
                        visited[j] = 1;
                    }
    
                    // 如果到达目标城市,更新最短路径
                    if (que[tail - 1].x == end) {
                        if (que[tail - 1].getS() < min) {
    
                            // 更新最小值
                            min = que[tail - 1].getS();
    
                            // 为了让访问过的目标重新能够被访问到
                            visited[que[tail - 1].getX()] = 0;
    
                            // 为了避免数组溢出
                            tail--;
                            break;
                        }
                    }
                }
    
                head++;
            }
    
            System.out.println(min); // 9
        }
    
  • 弗洛伊德算法Floyd

        /**
         * 核心代码
         */
        public void getCore() {
    
            // crossVertexes记录从顶点i到顶点j途经的最后一个顶点
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    if (edges[i][j] < INF) {
                        crossVertexes[i][j] = j;
                    } else {
                        crossVertexes[i][j] = -1;
                    }
                }
            }
    
    //        for (int i = 0; i < 4; i++) {
    //            for (int j = 0; j < 4; j++) {
    //                System.out.print(crossVertexes[i][j] + " ");
    //            }
    //            System.out.println();
    //        }
    
            // 从顶点i到顶点j途经顶点k的最短路径
            for (int k = 0; k < size; k++) {
                for (int i = 0; i < size; i++) {
                    for (int j = 0; j < size; j++) {
                        if (edges[i][k] < INF && edges[k][j] < INF && edges[i][j] > edges[i][k] + edges[k][j]) {
                            edges[i][j] = edges[i][k] + edges[k][j];
                            // 关键代码(容易出错的地方)
                            crossVertexes[i][j] = crossVertexes[i][k];
                        }
                    }
                }
    //            System.out.println("-----------------");
    //            for (int i = 0; i < 4; i ++) {
    //                for (int j = 0; j < 4; j ++) {
    //                    System.out.print(edges[i][j] + " ");
    //                }
    //                System.out.println();
    //            }
    
                System.out.println("-----------------");
                for (int i = 0; i < 4; i++) {
                    for (int j = 0; j < 4; j++) {
                        System.out.print(crossVertexes[i][j] + " ");
                    }
                    System.out.println();
                }
            }
        }
    
  • 迪杰斯特算法Dijkstra

        public static void getCore(int n, int v0) {
    
            // dis数组保存0到其余各个顶点的初始路程
            if (n >= 0) System.arraycopy(e[v0], 0, dis, 0, n);
    
            // 表示i号顶点是否已经在P集合中
            for (int i = 0; i < n; i ++) {
                visited[i] = 0;
    
                if (dis[i] < INF) {
                    prev[i] = v0;
                } else {
                    prev[i] = -1;
                }
            }
    
            visited[v0] = 1;
    
            // 算法核心
            for (int i = 0; i < n - 1; i ++) {
    
                int min = INF;
                int u = 0;
    
                // 寻找剩余顶点到源点的最短路径
                for (int j = 0; j < n; j ++) {
                    if (visited[j] == 0 && dis[j] < min) {
                        min = dis[j];
                        u = j;
                    }
                }
    
                visited[u] = 1;
                System.out.println("×××" + u);
    
                // 松弛操作
                for (int k = 0; k < n; k ++) {
                    if (e[u][k] < INF) {
                        if (dis[k] > min + e[u][k]) {
                            dis[k] = min + e[u][k];
                            prev[k] = u;
                        }
                    }
                }
            }
        }