首先,圖論中的最小生成樹問題就是給出乙個大小為n*m鄰接矩陣或者n個頂點m條邊(包含每條邊路徑花費)的資料,讓我們計算使得這n個頂點直接或間接聯通所需要的最小花費。
其次,所給的資料分為稀疏圖和稠密圖,對於乙個圖,理論上n個頂點可以有n*(n-1)條邊,如果該圖中存在的邊數m遠小於n*(n-1),可以稱之為稀疏圖,如果該圖中存在的邊數m接近n*(n-1),可以稱之為稠密圖。
接下來,先總結一下prim演算法。我們將圖中所有的頂點分為兩類:樹頂點(已被選入生成樹的頂點)和非樹頂點(還未被選入生成樹的頂點)。首先選擇任意乙個頂點加入生成樹。接下來要找出一條邊新增到生成樹,這需要列舉每乙個樹頂點到每乙個非樹頂點所有的邊,然後找到最短邊加入到生成樹。按照此方法重複n-1次,直到將所有頂點都加入到生成樹中。
prim演算法模板題:
ac**:
1 #include2 #includeview code3int e[1100][1100],book[1100],dis[1100]; //
頂點數n<=1000
4const
int inf=99999999
;
5int
main()630
}31 book[j]=1; //
標記該點被訪問過
32 c++; //
計加入的頂點數
33 sum += dis[j]; //
累計花費
34for(k=1;k<=n;k++) //
更新生成樹到各各非樹頂點的距離
3539
}40 printf("
%d\n
",sum);
41}
42return0;
43 }
上述演算法的時間複雜度是o(n*n),適用於頂點數較少的稠密圖(因為頂點數太多,一是開不了那麼大的陣列,二是容易超時)。如果陣列開不了那麼大,又想用prim演算法的話,可以使用鄰接表來儲存圖,但是這裡更推薦使用kruskal演算法,因為較容易實現,不侷限於陣列的大小,效率也很高。
再總結一下kruskal演算法,首先將邊按照邊的權值進行從小到大排序,每次從剩餘的邊中選擇權值較小且邊的兩個頂點不在同乙個集合內的邊(即不會產生迴路的邊),加入到生成樹中,直到加入了n-1條邊為止。
kruskal演算法模板題:
ac**:
1 #include2 #includeview code3struct
edge4;
7struct edge e[1000010
];8 #include9
using
namespace
std;
10bool cmp(struct edge x,struct
edge y)
11 12
int f[100010
];13
int merge(int v,int
u);14
int getf(int
v);15
intmain()
1634
if(c==n-1)35
break;36
}37 printf("
%d\n
",sum);38}
39return0;
40}
41int getf(int
v)42
45int merge(int v,int
u)46
55return
0; //
返回0表示能構成迴路,不可以建造這條路
56 }
上述演算法的時間複雜度為o(mlogm),綜合來說效率還是很高的,適用於稀疏圖。
最後,總的來說最小生成樹中kruskal演算法還是較優的,應優先使用。
最小生成樹模板
prim演算法理解可以參考部落格 prim演算法模板 int prime int v int i,j,sum 0,min,k sum是權重和 for i 1 i n i lowcost i 表明當前狀態下在u內距離v點 s中各點 距離的最小值,每個u中點s 中點 都計算 lowcost i map ...
最小生成樹 模板
const int maxn 1010 const int maxm 200020 struct edge edges maxm int father maxn int find int x int cmp edge a,edge b 將邊按權值排序 int kruskal int n,int m ...
模板 最小生成樹
題目描述 如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz 輸入輸出格式 輸入格式 第一行包含兩個整數n m,表示該圖共有n個結點和m條無向邊。n 5000,m 200000 接下來m行每行包含三個整數xi yi zi,表示有一條長度為zi的無向邊連線結點xi yi 輸出格式 輸出...