最小生成樹Prim
最小生成樹的定義
一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊(度娘原話)
簡單來說,就是一個連接所有點且路徑和最小的圖
Prim的思路
設圖的頂點集合為U,樹的頂點集合為V
從圖中任意一點出發,找到N-1條邊(x,y),x∈U,y∈V,且權值最小。
通俗的講,就是不斷找權值最小且不產生閉環的N-1條邊
栗子
廢話不多說,先上圖
如下圖所示
(1)從V3出發
(2)找到邊(V3,V1),符合條件且最小,將V1加入V
以此類推……
(N)找到邊(V2,V5),符合條件且最小,將V5加入V,最小生成樹構造完成
代碼(C++)
雖然是P黨,但考慮到Pascal受眾較小,我采用C++
代碼巨丑,bug一堆,歡迎巨佬吐槽
務必記住,要將A的初值定為正無窮,不然會卡BUG
/*Prim核心代碼 HYDcn原創*/
for (int i=2;i<=n;i++) { lowcost[i]=a[i][1];//將與V1(或任意一點)有關的邊存入lowcost(與各點最小權值)
} for (int i=1;i<n;i++) { minval=1000000;//初始化最小值為正無窮
for (int j=1;j<=n;j++) { if (lowcost[j]>0&&lowcost[j]<minval)//如果當前權值不為0(即未連接過)且更小
{ k=j;//記錄當前點
minval=lowcost[j];//將最小值存入
} } ans+=minval;//統計最小生成樹最小權值和
lowcost[k]=0;//標記該點
for (int j=1;j<=n;j++) { if (lowcost[j]>0&&lowcost[j]>a[k][j])//由於U集合點增加,需更新與各點最小權值邊
{ lowcost[j]=a[k][j]; } } }
輸入
7 9
1 2 28
1 6 10
2 3 16
2 7 14
3 4 12
4 5 22
4 7 18
5 6 25
5 7 24
輸出
99(即權值和)
算法對比
Prim和Kruskal都是最小生成樹算法
據說Prim算法適用於稠密圖 Kruskal適用於稀疏圖
不知道你們信不信,反正我是不信,因為我被親身卡過
(QAQ算法歧視)
Prim:O(N^2)
Kruskal:O(M log M)
Kruskal在絕大部分情況下不會卡,而Prim很容易被卡
能用Kruskal還是盡量用吧