D07【模板】最小生成树 Prim 算法
D07 最小生成树 Prim 算法——信息学奥赛算法_哔哩哔哩_bilibili
我们定义无向连通图的 最小生成树(Minimum Spanning Tree,MST)为边权和最小的生成树.
注意:只有连通图才有生成树,而对于非连通图,只存在生成森林.
Prim 算法
Prim 算法 基本思想是从一个结点开始,不断加点(而不是 Kruskal 算法的加边).
从任意一个结点开始,将结点分成两类:已加入的,未加入的.
每次从未加入的结点中,找一个与已加入的结点之间边权最小值最小的结点.
然后将这个结点加入,并连上那条边权最小的边.
重复 𝑛 −1
次即可.
// 堆优化的 Prim 算法 O(mlogm) #include<bits/stdc++.h> using namespace std; #define inf 1e9 const int N=5010; int n,m,ans,cnt; vector<pair<int,int>> e[N]; int d[N],vis[N]; //d[v]表示v到已选集合的最短距离 bool prim(int s){ for(int i=0;i<=n;i++) d[i]=inf; d[s]=0; priority_queue<pair<int,int>> q; //大根 q.push({0,s}); //起点入队 while(q.size()){ int u=q.top().second; q.pop(); if(vis[u]) continue; //第1次出队才扩展 vis[u]=1; ans+=d[u]; //边权和 cnt++; //节点个数 for(auto t:e[u]){ int v=t.first, w=t.second; if(d[v]>w){ //松弛 d[v]=w; q.push({-d[v],v}); //入队 } } } return cnt==n; } int main(){ cin>>n>>m; for(int i=1,a,b,c; i<=m; i++){ cin>>a>>b>>c; e[a].push_back({b,c}); e[b].push_back({a,c}); } if(!prim(1)) puts("orz"); else printf("%d\n",ans); }
// Prim算法 O(n^2+m) #include<bits/stdc++.h> using namespace std; #define inf 1e9 #define N 5010 int n,m,a,b,c,ans,cnt; vector<pair<int,int>> e[N]; int d[N],vis[N]; bool prim(int s){ for(int i=0;i<=n;i++) d[i]=inf; d[s]=0; for(int i=1;i<=n;i++){ int u=0; for(int j=1;j<=n;j++) if(!vis[j]&&d[j]<d[u]) u=j; vis[u]=1; //选u ans+=d[u]; //树边和 if(d[u]!=inf) cnt++; //点数 for(auto x:e[u]){ int v=x.first,w=x.second; if(d[v]>w) d[v]=w; //松弛 } } return cnt==n; } int main(){ cin>>n>>m; for(int i=0; i<m; i++){ cin>>a>>b>>c; e[a].push_back({b,c}); e[b].push_back({a,c}); } if(!prim(1)) puts("orz"); else printf("%d\n",ans); }
浙公网安备 33010602011771号