搜尋框中搜尋這篇部落格即可,已做遷移,支援一下咯~
給定一張帶權無向圖 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...
最小生成樹總結
研究了一天最小生成樹 衍生出來包括最小瓶頸樹,次小生成樹,最小樹形圖之類的演算法,前兩者基本能搞定,最後那個就。不太懂了日後再回去看吧似乎很少用到,抄個模板以備不時之需 先談談最小瓶頸樹 首先注意這兩個定理 命題 無向圖的最小生成樹一定是瓶頸生成樹。命題 瓶頸生成樹不一定是最小生成樹 好了 知道這個...