乾貨 最小生成樹總結

2021-10-10 08:09:25 字數 3357 閱讀 3537

搜尋框中搜尋這篇部落格即可,已做遷移,支援一下咯~

給定一張帶權無向圖 g=(

v,e)

,n=∣

v∣,m

=∣e∣

g=(v,e),n = |v|, m = |e|

g=(v,e

),n=

∣v∣,

m=∣e

∣。由 v

vv 中全部 n

nn 個頂點和 e

ee 中 n−1

n-1n−

1 條邊構成的無向連通子圖被稱為 g

gg 的一棵生成樹。邊權和最小的生成樹被稱為無向圖 g

gg 的最小生成樹(minimum spanning tree,mst)。

1.任意一棵最小生成樹一定包含無向圖中權值最小的邊。

證:反證法。假設無向圖存在一棵不包含權值最小邊的最小生成樹。若把這條權值最小邊插入到樹中,會形成乙個環,且環上的其他每條邊的權值都比這條插入的邊大,因此,用這條插入的邊替換環中任意一條邊都能得到更小的生成樹,與假設矛盾。

2.推論:給定一張帶權無向圖 g=(

v,e)

,n=∣

v∣,m

=∣e∣

g=(v,e),n = |v|, m = |e|

g=(v,e

),n=

∣v∣,

m=∣e

∣。從 e

ee 中選出 k

1k< n-1

k1 條邊構成 g

gg 的乙個生成森林。若再從剩下的 m−k

m-km−

k 條邊中選 n−1

−k

n-1-k

n−1−

k 條新增到生成森林中,使其成為 g

gg 的生成樹,並且保證後選的邊權值之和最小,則該生成樹一定包含這 m−k

m-km−

k 條邊中連線生成森林的兩個不連通節點的權值最小的邊。

暫時不太知道怎麼應用這兩個結論證明下文的兩個演算法,這裡僅做介紹

建立並查集,每個點各自為乙個集合。

每條邊按照權值從小到大排序,遍歷每條邊(x,y,z)。

若x,y屬於同個集合,則忽略這條邊,掃瞄下乙個邊。

否則,合併x,y所在的集合,並把z加到答案中。

掃瞄完所有邊後,第4步中所加的邊構成最小生成樹。

時間複雜度為o(m

logm

)o(mlogm)

o(mlog

m)。

因此,新得到的樹 m

mm 與 k

kk 具有相同代價。

依次類推,把a1,

a2,.

..,a

ma_1,a_2,...,a_m

a1​,a2

​,..

.,am

​的邊逐漸加到 m

mm 中,最終得到的樹 v

vv 與 m

mm 代價相同。

證必。

#include

using

namespace std;

const

int maxn =

2e5+10;

struct node

}edge[maxn]

;int fa[maxn]

;int

find

(int x)

intmain()

sort

(edge,edge+m)

;for

(int i =

1; i <=n; i++

)int cnt =

0, ans =0;

//cnt存加入森林的邊數,判斷是否存在生成樹,若邊樹等於n-1,則存在生成樹。

for(

int i =

0; i< m; i++)if

(cnt != n-1)

puts

("impossible");

else cout << ans << endl;

}

維護乙個陣列d:若x∈s,則d[x]表示節點x到集合t的距離。若x∈t,則d[x]就等於x被加入到t時選出的最小邊的權值。

用乙個sta陣列標記節點是否屬於t。每次從未被標記的節點中選取d值最小的,把它標記(加入t中),同時掃瞄所有出邊,更新另乙個端點的d值。最後,最小生成樹的權值總和為∑x=

2nd[

x]

\sum_^d[x]

∑x=2n​

d[x]

prim無優化版本

#include

using

namespace std;

const

int maxn =

1e3+10;

int mp[maxn]

[maxn]

, d[maxn]

, n, m;

bool sta[maxn]

;int

prim()

if(i) res +

= d[x]

;//第一次迴圈找的是1號點,不用加邊權

}return res;

}int

main()

int ans =

prim()

;if(ans ==

0x3f3f3f3f

)//返回無窮大說明無最小生成樹,輸出impossible

puts

("impossible");

else

cout << ans << endl;

}

優先佇列優化

#include

using

namespace std;

const

int maxn =

1e3+10;

int mp[maxn]

[maxn]

, d[maxn]

, n, m;

bool sta[maxn]

;int cnt;

intprim()

);while

(cnt < n && q.

size()

));//把更新過的值壓入佇列待匹配,這裡取負號是因為我們要取最小值,而優先佇列預設輸出最大值}}

}return res;

}int

main()

int ans =

prim()

;if(cnt != n)

//集合中沒有n個點說明不存在最小生成樹

puts

("impossible");

else

cout << ans << endl;

}

最小生成樹總結

給定一張圖,圖中有許多的節點還有許多長度不同的邊將這些點點相互連線,找出連線所有點的最短方式就是最小生成樹,可以證明,這樣一種最小的情況是不會出現環的,由於所有的無環圖都可以看做樹,所以成為最小生成樹。頂層思想是分治,選擇策略是貪心,實現方法如下 以邊為中心,先將所有的邊從小到大進行排序,之後依照大...

最小生成樹總結

啊,先紀念一下吧,難得一天這麼 666 ac 完了所有題 次小生成樹 看懂 今天學到了最小生成樹演算法中的 prim 演算法和kruskal 演算法。從巨集觀上來講 prim 更適合稠密圖,krustal 更適合稀疏圖,但對於我們來說暫時沒有什麼區別啦。prim 演算法中主要注意的點是 在visit...

最小生成樹總結

研究了一天最小生成樹 衍生出來包括最小瓶頸樹,次小生成樹,最小樹形圖之類的演算法,前兩者基本能搞定,最後那個就。不太懂了日後再回去看吧似乎很少用到,抄個模板以備不時之需 先談談最小瓶頸樹 首先注意這兩個定理 命題 無向圖的最小生成樹一定是瓶頸生成樹。命題 瓶頸生成樹不一定是最小生成樹 好了 知道這個...