普里姆算法(Prim)與最小生成樹問題


普里姆算法

@anthor:QYX

普里姆算法在找最小生成樹時,將頂點分為兩類,一類是在查找的過程中已經包含在樹中的(假設為 A 類),剩下的是另一類(假設為 B 類)。

對於給定的連通網,起始狀態全部頂點都歸為 B 類。在找最小生成樹時,選定任意一個頂點作為起始點,並將之從 B 類移至 A 類;然后找出 B 類中到 A 類中的頂點之間權值最小的頂點,將之從 B 類移至 A 類,如此重復,直到 B 類中沒有頂點為止。所走過的頂點和邊就是該連通圖的最小生成樹。

例如,通過普里姆算法查找圖 2(a)的最小生成樹的步驟為:

假如從頂點A出發,頂點 B、C、D 到頂點 A 的權值分別為 2、4、2,所以,對於頂點 A 來說,頂點 B 和頂點 D 到 A 的權值最小,假設先找到的頂點 B:


繼續分析頂點 C 和 D,頂點 C 到 B 的權值為 3,到 A 的權值為 4;頂點 D 到 A 的權值為 2,到 B 的權值為無窮大(如果之間沒有直接通路,設定權值為無窮大)。所以頂點 D 到 A 的權值最小:


最后,只剩下頂點 C,到 A 的權值為 4,到 B 的權值和到 D 的權值一樣大,為 3。所以該連通圖有兩個最小生成樹:

 

另一個例子:

 

 

package com.qyx.Tree;
import java.util.Arrays;
/**
 * prim算法最小生成樹解決修路問題
 * @author Administrator
 *
 */
public class PrimAlgorithm {
    public static void main(String[] args) {
        //測試圖是否創建成功
        char[] data=new char[]{'A','B','C','D','E','F','G'};
        int verxs=data.length;
        //鄰接矩陣使用二維數組表示
        int[][] weight=new int[][]{
            //A      B      C      D      E      F      G
            {10000,5,7,10000,10000,10000,2}, //A    
            {5,10000,10000,9,10000,10000,3}, //B
            {7,10000,10000,10000,8,10000,10000}, //C
            {10000,9,10000,10000,10000,4,10000}, //D
            {10000,10000,8,10000,10000,5,4}, //E
            {10000,10000,10000,4,5,10000,6}, //F
            {2,3,10000,10000,4,6,10000}, //G
        };
        MGraph mgraph=new MGraph(verxs);
        MinTree minTree=new MinTree();
        minTree.createGraph(mgraph, verxs, data, weight);
        minTree.showGraph(mgraph);
        //測試普利姆算法
        minTree.prim(mgraph, 0);
    }

}
//創建最小生成樹->村庄的圖
class MinTree{
    //創建圖的鄰接矩陣
    /**
     * 
     * @param graph 圖對象
     * @param verxs 圖對應的頂點個數
     * @param data 圖的各個頂點的值
     * @param weight 圖的領結矩陣
     */
    public void createGraph(MGraph graph,int verxs,char data[],int[][] weight)
    {
        int i,j;
        for(i=0;i<verxs;i++) //定點
        {
            graph.data[i]=data[i];
            for(j=0;j<verxs;j++)
            {
                graph.weight[i][j]=weight[i][j];
            }
        }
    }
    //顯示圖的鄰接矩陣
    public void showGraph(MGraph graph)
    {
        for(int[] link:graph.weight)
        {
            System.out.println(Arrays.toString(link));
        }
    }
    //編寫prim算法,得到最小生成樹
    /**
     * 
     * @param graph 圖
     * @param v 表示從圖的第幾個頂點開始生成
     */
    public void prim(MGraph graph,int v)
    {
        //標記節點是否被訪問過
        boolean visited[]=new boolean[graph.verx];
        for(int i=0;i<graph.verx;i++)
        {
            visited[i]=false;
        }
        //把當前這個節點標記為已訪問
        visited[v]=true;
        //h1和h2記錄兩個頂點的下標
        int h1=-1;
        int h2=-1;
        int minWeight=10000;//將其先初始為一個大數,后面在遍歷過程中會被替換
        //確定每一次生成的子圖和哪個節點距離最近
        for(int k=1;k<graph.verx;k++){
            //在n個節點下,會有n-1條邊
            for(int i=0;i<graph.verx;i++) //i表示被訪問過的結點
            {
                for(int j=0;j<graph.verx;j++) //j結點表示還沒有訪問過的結點
                {
                    if(visited[i]==true&&visited[j]==false&&graph.weight[i][j]<minWeight)
                    {
                        //替換minWeight(尋找已經訪問過的結點和未訪問過的結點間的權值最小的邊)
                        minWeight=graph.weight[i][j];
                        h1=i;
                        h2=j;
                    }
                }
            }
            //找了一條邊是最小的,將當前這個結點標記為已經訪問
            System.out.println(h1+"->"+h2+"權值為"+minWeight);
            visited[h2]=true;
            //minWeight重新設置為最大值
            minWeight=10000;
        }
    }
}
class MGraph{
    int verx;//表示圖的節點個數
    char[] data;//存放節點的數據
    int[][] weight;//存放邊,就是我們的鄰接矩陣
    public MGraph(int verx) {
        this.verx=verx;
        data=new char[verx];
        weight=new int[verx][verx];
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM