图的最短路径问题

今天一定要把图的最短路径给解决了。

(1)Floyd算法。O(n^3)。但是代码极其简介。

试用范围:求任意两点之间的最短路径。(Dijkstra。迪克斯特拉是求某个顶点到其他任何顶点的。对他的n个顶点都来一次Dijkstra等价于Floyd。复杂度是他的O(n^2)*n == O(n^3))。

思路和代码:其实就是说i直接到j的距离如果比i到了k,k再到j之和大,那么久更替。k可以取所有顶点。

import java.util.Arrays;

public class Main {
    public final static int INFINITY = Integer.MAX_VALUE;
    public static void main(String[] args) {
        int[][] graph = { { 0, 2, 6, 4}, { INFINITY, 0, 3, INFINITY}, { 7, INFINITY, 0, 1}, { 5, INFINITY, 12, 0}};
        floyd(graph);
        for (int i = 0; i < 4; i++) {
            System.out.println(Arrays.toString(graph[i]));
        }
    }
    
    public static void floyd(int[][] graph) {
        for (int k = 0; k < graph.length; k++) {
            for (int i = 0; i < graph.length; i++) {
                for (int j = 0; j < graph.length; j++) {
                    if (graph[i][k] < INFINITY && graph[k][j] < INFINITY && graph[i][j] > graph[i][k] + graph[k][j]) {
                        graph[i][j] = graph[i][k] + graph[k][j];
                    }
                }
            }
        }
    }
}
View Code

 

(2)Dijkstra算法。O(n^2)。

试用范围:求指定的一个点v0到其余各个顶点的最短路径。专业术语:单源最短路径。在函数上可以随意指定要求哪个点到哪个点

思路:建立一个distance[n]来表示到所有点的距离。首先,把第一行拷贝了。哪个点是源点,那么distance[v0] == 0;

代码:

import java.util.Arrays;

public class Main {
    public final static int INFINITY = Integer.MAX_VALUE;
    public static void main(String[] args) {
        int[][] graph = { { 0, 2, 6, 4}, { INFINITY, 0, 3, INFINITY}, { 7, INFINITY, 0, 1}, { 5, INFINITY, 12, 0}};
//        floyd(graph);
//        for (int i = 0; i < 4; i++) {
//            System.out.println(Arrays.toString(graph[i]));
//        }
        int[] distance = new int[graph.length];
        dijsktra(graph, distance, 1);
        System.out.println(Arrays.toString(distance));
        
    }
    public static void dijsktra(int[][] graph, int[] distance, int v0) { // 从v0到其他顶点的路径
        boolean[] finish = new boolean[graph.length];
        for (int i = 0; i < graph.length; i++) {
            distance[i] = graph[v0][i];
        }
        finish[v0] = true;
        distance[v0] = 0;
        int minIndex = -1;
        for (int n = 1; n < graph.length; n++) { // n次
            int min = Integer.MAX_VALUE;
            for (int i = 0; i < graph.length; i++) {
                if (!finish[i]) {
                    if (distance[i] < min) {
                        min = distance[i];
                        minIndex = i;
                    }
                }
            }
            finish[minIndex] = true;
            for (int i = 0; i < graph.length; i++) {
                if (!finish[i]) {
                    if (graph[minIndex][i] < INFINITY && graph[minIndex][i] + min < distance[i]) {
                        distance[i] = min + graph[minIndex][i];
                    }
                }
            }
        }
    }
}
View Code

如果是求第一个到最后一个,可以优化为:

public static int dijsktraLast(int[][] graph, int[] distance, int v0) { // 从v0到其他顶点的路径
        boolean[] finish = new boolean[graph.length];
        for (int i = 0; i < graph.length; i++) {
            distance[i] = graph[v0][i];
        }
        finish[v0] = true;
        
//        distance[v0] = 0;
        int minIndex = -1;
        for (int n = 1; n < graph.length; n++) { // n次
            int min = Integer.MAX_VALUE;
            for (int i = 0; i < graph.length; i++) {
                if (!finish[i]) {
                    if (distance[i] < min) {
                        min = distance[i];
                        minIndex = i;
                    }
                }
            }
            if (minIndex == graph.length - 1) {
                return min;
            }
            finish[minIndex] = true;
            
            for (int i = 0; i < graph.length; i++) {
                if (!finish[i]) {
                    if (graph[minIndex][i] < INFINITY && graph[minIndex][i] + min < distance[i]) {
                        distance[i] = min + graph[minIndex][i];
                    }
                }
            }
        }
        return distance[graph.length - 1];
    }
View Code

 

(3)Bellman-ford算法。O(NM)

试用范围:稀疏图。可以解决负权

思路和代码:其实就是建立一个u[i]顶点到v[i]顶点的权值为w[i]。

 代码:

import java.util.Arrays;

public class Main {

    public static int INFINITY = Integer.MAX_VALUE;
    public static void main(String[] args) {
        int[] u = {0, 0, 0, 1, 2, 2, 3, 3};
        int[] v = {3, 2, 1, 2, 0, 3, 2, 0}; 
        int[] w = {4, 6, 2, 3, 7, 1, 12, 5 };
        int n = 4;
        int m = 8;
        int[] distance = new int[n];
        bellmanFord(distance, u, v, w, n, m, 3);
        System.out.println(Arrays.toString(distance));
    }
    public static void bellmanFord(int[] distance, int[] u, int[] v, int[] w, int n, int m, int start) { // start 表示第几个顶点到其他的
        for (int i = 0; i < n; i++) {
            distance[i] = INFINITY;
        }
        distance[start] = 0;
        for (int k = 0; k <= n - 1; k++) { //需要来进行n-1轮
            int check = 0;
            for (int i = 0; i < m; i++) {
                if (distance[u[i]] != INFINITY && distance[v[i]] > distance[u[i]] + w[i]) {
                    distance[v[i]] = distance[u[i]] + w[i];
                    check = 1;
                }
            }
            if (check == 0) {
                break;
            }
        }
    }
}
View Code

 

 

posted @ 2016-04-05 10:18  创业-李春跃-增长黑客  阅读(554)  评论(0编辑  收藏  举报