1. 程式人生 > >(原創)最小生成樹之Prim(普裏姆)算法+代碼詳解,最懂你的講解

(原創)最小生成樹之Prim(普裏姆)算法+代碼詳解,最懂你的講解

class bsp 簡單 相加 置0 思路 cost 數組 print

Prim算法

(哈欠)在創建最小生成樹之前,讓我們回憶一下什麽是最小生成樹。最小生成樹即在一個待權值的圖(即網結構)中用一個七拐八繞的折線串連起所有的點,最小嘛,顧名思義,要權值相加起來最小,你當然可以拿起筆來就算你腦中的每一種可能,但是如果你了解了這種算法,你就能跟我一樣,一次畫出完美答案。

上個栗子:

技術分享圖片

我先說一哈這個算法的方法論,然後我們來代碼實現一下,在講解開始之前,敲黑板,記得我們要生成一個權值最小的樹,所以每一步都要考慮到樹的每一個結點,不要孤立地用一個結點來對比從而走上死路,我們任選一個點開始生成,教材裏選的 v0,那我們就選 v8,戰鬥開始

v8 有三條路,分別通往v1 v2 v3,v2那條路權值最小,ok, v2→v8,然後我們該看什麽,如果你說找和 v2 相鄰的 v8 以外的邊,那我剛才的強調就gg了,我們找v2 和 v8除相連的線之外的所有分支,易得 v8→v1的權值最小,ok,下一步找哪幾個點?v2 v1 v8這三個點除兩條連接線以外的所有分支,挑最小的那一條,後面重復前面的操作,每次都把新加入的夥伴算在找線之內才對,自己畫一下給答案:

技術分享圖片

操作一遍是不是發現還真的跟哪個點開始沒雞兒關系,因為每個點都要連到,關鍵就在於沿最小分支找點的時候一定要把它看成一個樹結構來找,才算是最小生成樹。

還是給一下標準定義:

我們把構造連通網的最小代價(權值)生成樹 稱為最小生成樹 (Minimum Cost Spanning Tree)。

方法論就到這裏,相信下一次看到同樣的現實問題,你也應該能在第一時間用正確的思路找到合適的路。

在代碼實現之前,我們先請來連通圖的好基友——鄰接矩陣

技術分享圖片

我們發現一行一行的矩陣很容易顯示權值,這樣就可以快速對比權值的大小,只要在循環的每一步留存下權值較小的邊權值和頂點下標,就可以實現。

和以前一樣,我們還是用 INFINITY 來表示無限大,即不存在該邊

代碼如下:

 1 void MiniSpanTree_Prim(MGragh G)
 2 {
 3     int mini,i,j,k;
 4     int adjvex[MAXVEX]; //保存相關頂點下標
 5     int lowcost[MAXVEX]; //保存相關頂點間邊的權值
 6     lowcost[0] = 0;//這裏把第0位的權值置0表示v0已加入生成樹
 7     //ps:lowcost[i] = 0 表示i那個下標的頂點加入生成樹
 8     adjvex[0] = 0; //初始化第一個頂點的下標為0
9 for(i = 0; i < G.numVertexes; i++) 10 { 11 lowcost[i] = G.arc[0][i];//將vo相關頂點的權值存入lowcost數組 12 adjvex[i] = 0;//置所有下標為v0 13 } 14 for(i = 1; i < G.numVertexes; i++) //最小生成樹開始遼 15 { 16 mini = INFITINY; //先把權值的最小值置為無限大 17 j = 1; 18 k = 0; 19 while(j < G.numVertexes) 20 { 21 if(lowcost[j] != 0 && lowcost[j] < mini)//判斷並向lowcost中添加權值 22 { 23 mini = lowcost[j]; 24 k = j; 25 } 26 j++; 27 } 28 printf("(%d %d)",lowcost[k],k); 29 lowcost[k] = 0;//置0表示這個定點已經完成任務,找到最小權值分支 30 for(j = 1; j < G.numVertexes; j++) 31 { 32 if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j]) 33 { 34 lowcost[j] = G.arc[k][j]; 35 adjvex[j] = k; 36 } 37 } 38 } 39 }

簡單講解一哈:

  • 4~5行,先說 adjvex[] ,這個數組要解決的問題就是存入已經安排好的那些頂點的下標,什麽叫安排好了呢,比如我已經找到了 v0→v1 ,v1 就可以算是安排好了,而v0點置0則算做初始化的操作;再說 lowcost[] 這個數組,聽名字就是最小權值的意思,下面講循環的時候詳解這個東西到底儲存了些什麽,然後每次更新之後能做什麽
  • 6~13行完全是初始化,要註意的是就是 lowcost[] 儲存了鄰接矩陣 v0 這一行的權值
  • 14~38行是最小生成樹的整體代碼
  • 16行就是每次都把最小值重置
  • 19~27行,從 1 開始遍歷完全,找到現在這個狀態下的最小權值數,並且把這個下標用 k 存住,28行就是把權值和下標打印出來,當然也可以換成別的操作,這裏不再贅述
  • 然後29行,看看他都幹了些什麽,它把 adjvex[ k ] 置0,看一下第一點,這裏表示 v1 完成任務,沒有利用價值了
  • 然後30~37這個循環,看看循環的條件,條件一: lowcost[ j ] != 0 ,這是啥意思,表示在沒有完成任務的頂點中選擇,條件二: G.arc[k][j] < lowcost[j] 這表示在剛才找到的新頂點的矩陣那一行去對應,如果有更小的權值就把 lowcost[] 更新掉,這樣就保證了這個數組中同時存在好幾個頂點的權值信息,還是擇優錄用的,然後返回循環頭,再找這次的最小權值點,周而復始。

時間復雜度 O(n²) ,沒啥問題遼

最後附上過程圖:

技術分享圖片

謝謝大嘎

(原創)最小生成樹之Prim(普裏姆)算法+代碼詳解,最懂你的講解