最小生成樹就是對於乙個連通圖,保留若干條邊,使圖依然聯通,且邊權和最小。
因為\(n\)個點的連通圖(以下自動預設為連通圖,),最少要有\(n-1\)條邊。所以對於乙個圖的最小生成樹,也一定只有\(n-1\)條邊。反證一下(此證明僅限於非負邊權):如果這個圖的最小生成樹不止有\(n-1\)條邊,因為只需保留\(n-1\)條邊即可保持聯通,所以我們一定可以找到一條邊,將其刪去,仍保持圖聯通。這樣的話就與我們的定義不符了。當然,對於存在負邊權的情況,顯然是不能這麼簡單證明的,所以我們這裡只討論正邊權。
由於最小生成樹的上述特性,\(kruskal\)演算法便應運而生了。
簡單的敘述就是:先把\(n\)個點分布在\(n\)個集合中,將\(m\)條邊從小到大排序,依次遍歷。如果當前邊所連線的兩個點不在同一集合,則加上這條邊,然後合併兩個集合;如果在同一集合則忽略。直到選擇了\(n-1\)條邊後,最小生成樹也就求出來了。這裡比較顯然,就不證明了。
題目鏈結
下面放**
#include#include#include#include#include#define ll long long
#define gc getchar
#define maxn 5005
#define maxm 200005
using namespace std;
inline ll read()
while(isdigit(p))
return f?-a:a;
}int n,m,sum,ans;
struct ahaha{
int u,v,w;
inline bool friend operator<(const ahaha x,const ahaha y){
return x.w除了\(kruskal\)以外,還有一種演算法叫做\(prim\)演算法。\(prim\)演算法簡單來說就是:先把乙個點放到集合\(b\)裡,然後把剩下的點放到集合\(a\)裡,每次把從集合\(a\)連向集合\(b\)的最短邊拿出來,然後把最短邊所連線的集合\(a\)中的點移動到集合\(b\)中,直到所有點都放到了集合\(b\)中,最小生成樹也就求好了。
由於我幾乎沒有用過這種演算法,這裡也就不放**了。
\(kruskal\)在稀疏圖中的複雜度更優秀,而\(prim\)在稠密圖中要更勝一籌,具體採用哪種方法,還要看大家的喜好還有題目要求。
至於題目推薦,這種型別的題太多了,我就不推薦了
如果這篇部落格對你有些許幫助的話,不妨點推薦再走吧
最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...
最小生成樹
package 圖 最小生成樹是用最少的邊吧把所有的節點連線起來。於是和圖的深度優先搜素差不多。class stack public void push int key public int pop 檢視棧頂的元素 public int peek public boolean isempty cla...
最小生成樹
define max vertex num 20 最大頂點數 typedef int adjmatrix max vertex num max vertex num 鄰接矩陣型別 typedef char vertextype typedef struct mgraph struct dnodecl...