最小生成樹問題一般對應無向圖,一般都有m≤n*n,所以mlogm和mlogn差不多,所以我們一般用kruskal而不常用堆優化的prim
1.樸素版prim
o(n2)
基本思路
初始化 dis[i]
<
- 正無窮大
for(i=
0;i) n次迭代,因為要加入n個點到集合中
t <
- 找到集合外距離最近的點
用 t 更新 其他點 -
> 「集合」 的距離 //dij是來更新到起點的距離
st[t]
=true
;//把t加到集合裡
優化方式和dij差不多
例題
稠密圖
輸入
451
2113
2143
2323
44
輸出6
**
#include
#include
#include
#include
const
int maxn=
510;
const
int inf=
0x3f3f3f3f
;using
namespace std;
int n,m;
int mp[maxn]
[maxn]
,dis[maxn]
;//dis表示點到集合的距離
bool st[maxn]
;int
prim()
return ans;
}int
main()
int ans=
prim()
;if(ans==inf)
cout<<
"impossible"
<
else
cout<
return0;
}
和dijstra演算法極為相似,只是更新那裡有一點不同:dis[j]=min(dis[j],mp[t][j]);
注意:最小生成樹時不能有自環的
所以如果存在乙個點它有負權自環,是不應該加進去的。如果for更新放在求權值和之後,可能會導致把負權自環更新過的dis加進去,這裡的順序要注意先進行累加。
以下寫法會導致兩次呼叫prim(),初始化會有問題,st會沒有初始化到
if
(prim()
==inf)
puts
(「impossible」)
;else cout<<
prim()
<
堆優化就是用 堆來維護dis,把時間複雜度降到o(1)
思路和**都比kruskal麻煩,所以不常用。
2.kruskal
o(mlogm)
時間主要花在排序上,但排序的常數很小,就是乙個logn進行運算的次數很少,所以通常時間上會表現得比較理論上好。
基本思路
1.將所有邊按權重從小到大排序//o(mlogm) 演算法的瓶頸
2.列舉每條邊 a,b,權重c //o(m)
if a,b不連通 //並查集判環
將這條邊加到集合中
例題
輸入
451
2113
2143
2323
44
輸出6
**#include
#include
#include
#include
const
int maxn=
1e5+5;
const
int inf=
0x3f3f3f3f
;using
namespace std;
int n,m;
struct node
}edges[
2*maxn]
;int p[maxn]
;//用來儲存並查集的父親節點
intfind
(int x)
//找到它們的祖宗結點
intkruskal()
}if(cnt
//一共n個點,如果沒有n-1條邊,說明不能全部連通
return inf;
return ans;
}int
main()
;}int ans=
kruskal()
;if(ans==inf)
cout<<
"impossible"
<
else
cout<
return0;
}
最小生成樹問題
1.構造可以使n個城市連線的最小生成樹。問題描述 給定乙個地區的n個城市間的距離網,用prim演算法或kruskal演算法建立最小生成樹,並計算得到的最小生成樹的代價。4 要求 1 城市間的距離網採用鄰接矩陣表示,鄰接矩陣的儲存結構定義採用課本中給出的定義,若兩個城市之間不存在道路,則將相應邊的權值...
最小生成樹問題
最小生成樹 是一棵樹 無迴路 個頂點一定有 條邊 包含全部頂點 條邊都在圖里 邊的權重和最小 生成約束 只能用圖里有的邊 只能正好用掉 條邊 不能有迴路 主要演算法 prim演算法 讓樹長大 int prim int n int ans 0 距離權值總和 vis 1 true 生成樹的根 起點 標記...
最小生成樹問題
最小生成樹 乙個有n個點的圖,邊一定是大於等於n 1條的。圖的最小生成樹,就是在這些邊中選擇n 1條出來,連線所有的n個點。這n 1條邊的邊權之和是所有方案中最小的。最小生成樹用來解決什麼問題?就是用來解決如何用最小的 代價 用n 1條邊連線n個點的問題。例題 洛谷p3366 乾坤大挪移 最小生成樹...