1.如今要選擇這樣一個生成樹,也就是使總耗費最少。這個問題就是構造連通網的最小代價生成樹(Minimum Cost Spanning Tree)簡稱爲最小生成樹的問題。一顆生成樹的代價就是樹上各邊的代價之和。java
構造最小生成樹的算法有多種。大多算法利用了最小生成樹的下列簡稱爲MST的特性:算法
假設N=(V,{E})是一個連通網,(N表明連通網,V表明網的各個頂點,E表明網的邊),U是頂點集V的一個非空子集。若(u,v)是一條具備最小權值的邊,其中u屬於U,v屬於V-U,則必存在一顆包含邊(u,v)的最小生成樹。數組
2.反證法證實上面MST特性:code
假設網N的任意一顆最小生成樹都不包含(u,v).設T是連通網上的一顆最小生成樹,當將邊(u,v)加入T中時,由生成樹的定義可知,T中必存在一條包含(u,v)的迴路。排序
另外一方面,因爲T是生成樹,則在T中必存在一條(u1,v1),其中u1屬於U,v1屬於V-U,且u,u1,v,v1必有路徑相通。刪去(u1,v1)即可消除上述迴路,同時獲得另外一顆生成樹T1。因爲(u,v)的代價不高於(u1,v1),則T1的代價不高於T,T1是包含(u,v)的一顆最小生成樹。由此可假設矛盾。索引
3.普里姆(prim)算法 get
假設N=(V,{E})是連通網,TE是N上最小的生成樹中邊的集合。算法從U={u0},(u0屬於V),TE={}開始,重複執行下述操做:在全部u屬於U,v屬於V-U的邊(u,v)屬於E中,尋找一條代價最小的邊(u0,v0)併入集合TE中,同時v0也併入集合U中,直到U=V爲止。此時TE中必有n-1條邊,而T=(V,{E})爲N的最小生成樹。io
爲實現這個算法,須要附設一個輔助數組closedge,以記錄從U到U-V具備最小代價的邊。對每一個頂點vi屬於V-U,在輔助數組中存在一個相應份量closedge[i-1],它包含兩個域,其中lowcost存儲該邊上的權。vex存儲附屬在該邊上的在U中的頂點。 class
/** * 普里姆算法,最小生成樹, * 從圖中第start個元素開始,生成最小樹 */ public void prim(int start) { Integer vexNum = mVexs.length; //頂點的個數 int index = 0;//prim最小樹的索引,即prims數組的索引 String[] prims = new String[vexNum]; //prim最小樹的結果數組 int[] weights = new int[vexNum]; //頂點間的權值 prims[index++] = mVexs[start].data; //prim生成樹的第一個頂點是從start開始的 /** * 初始化頂點的權值數組; * 將每一個頂點的權值初始化爲第start個頂點到該頂點的權值 */ for (int i = 0; i < vexNum; i++) { weights[i] = getWeight(start, i); } for (int i = 0; i < vexNum; i++) { if (start == i) { continue; //終止本次循環,進行下一次循環,break終止for中的循環,進行循環下面的語句 } int j = 0, k = 0, min = INF; //在未被加入最小生成樹的頂點中,找出權值最小的頂點 while (j < vexNum) { //當weights[j]=0時,意味着第j個頂點已經被排序過,或者說已經加入了最小生成樹中 if (weights[j] != 0 & weights[j] < min) { min = weights[j]; k = j; //將最小權值的頂點賦給k } j++; } /** * 通過上面的while循環,則知在未被加入到最小生成樹的頂點中,權值最小的是k * 將第k個頂點加入到prims數組中 */ prims[index++] = mVexs[k].data; //並將第k個頂點的權值標記爲0,意味着第k個頂點已經被排序過了或者說被加入到了最小生成樹的結果中 weights[k] = 0; //更新其餘頂點到最小生成樹中頂點的權值 for (j = 0; j < vexNum; j++) { //獲取第k個頂點到第j個頂點的權值 int tmp = getWeight(k, j); //當第j個頂點未在最小生成樹中,且第j個頂點到最小生成樹中頂點的權值須要更新時,即加入k頂點後,已再也不是最小權值時 if (weights[j] != 0 && tmp < weights[j]) { weights[j] = tmp; } } } /** * 當prim最小生成樹已經生成完畢時 * 計算最小生成樹的權值 */ int sum = 0; //要從第2個元素開始,索引爲1,由於要計算兩頂點之間的權值 for (int i = 1; i < index; i++) { int min = INF; //或者去prims[i]頂點在頂點中的位置 int n = getPostion(prims[i]); for (int j = 0; j < i; j++) { int m = getPostion(prims[j]); int tmp = getWeight(m, n); if (tmp < min) { min = tmp; } } sum += min; } /** * 打印最小生成樹 */ System.out.println("PRIM" + mVexs[start].data + "=" + sum); for (int i = 0; i < index; i++) { System.out.println(prims[i]); } }