天天看點

JAVA實踐最小生成樹-Prim算法前言實作功能中文版參考代碼實作結果END

前言

這個算法的普通版本時間複雜度是O(n^2),據說是可優化的。

鄰接表+最小堆。然而我并沒有去實作。

不過此未經優化的版本适合稠密圖,Kruskal解決稀疏圖,豈不美哉= =

好吧,我就是懶了

已實作利用最小堆+鄰接表優化:

http://blog.csdn.net/xubaifu1997/article/details/52068329

實作功能

實作最小生成樹路徑長度的計算

中文版參考

/**
 * Prim算法
 * 同樣假設所有頂點未連接配接
    6   9
    2   4   11
    3   5   13
    4   6   3
    5   6   4
    2   3   6
    4   5   7
    1   2   1
    3   4   9
    1   3   2
 *
 * 從頂點1開始,尋找頂與點1可連接配接所有的頂點
 *      找到
 *          1→2,權值為1
 *          1→3,權值為2
 *      選擇權值最低的2号頂點,連接配接頂點1、2;
 *
 * 尋找與頂點1、2可連接配接的所有頂點
 *      找到
 *          1→2(此點排除,2已被作為末端連接配接)
 *          1→3     權值2
 *          2→3     權值6
 *          2→4     權值11
 *      選擇1→3
 * 尋找1、2、3可連接配接的所有頂點
 *      (排除以1、2、3作為末端的選項)找到
 *          2→4     權值11
 *          3→4     權值9
 *          3→5     權值13
 *       選擇3→4
 *  其餘點的操作類似
 *
 *  這個過程中唯一的問題是,腦袋會受到最短路徑思想的影響
 *  假設
 *      1→2權值1
 *      1→3權值5
 *      選擇頂點4時,1→2→4的總長度是12
 *                   1→3→4的總長度為14
 *  碰到這樣一開始覺得好奇怪,後來畫了個圖,發現雖然1到4經過2,單條路徑長度最短,總體生成的樹卻更長
 *  3→1→2→4長度17
 *  2→1→3→4長度15
 *  是以每次選擇 距離[任意一個已連接配接末端頂點] 最短的頂點,而不是距離首個頂點最短的頂點
 *
 *  解決了疑問,馬上寫代碼
 */
           

代碼實作

public class MinGenerationTreePrim {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int Inf = ;
        int n, m, count, min, minIndex;
        int[][] vertexes;
        boolean[] isConnected;//如果某頂點作為末端頂點被連接配接,應該為true
        int[] dis;//存儲已連接配接頂點都未連接配接頂點的最短距離
        int sum = ;//存儲路徑長度
        n = in.nextInt();
        m = in.nextInt();
        vertexes = new int[n][n];
        isConnected = new boolean[n];
        dis = new int[n];

        for (int i = ; i < n; i++) {
            for (int j = ; j < n; j++) {
                if (i == j) {
                    vertexes[i][j] = ;
                } else {
                    vertexes[i][j] = Inf;
                }
            }
        }

        for (int i = , a, b, c; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();
            c = in.nextInt();
            vertexes[a - ][b - ] = c;
            vertexes[b - ][a - ] = c;
        }

        //初始化dis數組
        minIndex = ;
        count = ;
        for (int i = ; i < n; i++) {
            dis[i] = vertexes[][i];
        }
        while (count < n) {
            min = Inf;
            //尋找權值最小的
            for (int i = ; i < n; i++) {
                if (!isConnected[i] && dis[i] < min) {
                    min = dis[i];
                    minIndex = i;
                }
            }
            sum += min;
            //System.out.println(min);
            isConnected[minIndex] = true;
            count++;
            //在minIndex之前的所有頂點已經對dis更新過了
            //是以隻需要更新minIndex頂點到其他頂點是否還有更短的距離
            for (int i = ; i < n; i++) {
                if (!isConnected[i] && dis[i] > vertexes[minIndex][i]) {
                    dis[i] = vertexes[minIndex][i];
                }
            }
        }
        System.out.println(sum);
    }
}
           

結果

輸入
    6   9
    2   4   11
    3   5   13
    4   6   3
    5   6   4
    2   3   6
    4   5   7
    1   2   1
    3   4   9
    1   3   2
輸出
19
           

END