假设 n 表示图中点数,m 表示图中边数。
Prim算法堆优化
时间复杂度 O(nlogn)。
核心思想:每次挑一条与当前集合相连的最短边。
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| int ans,cnt; struct edge{int v,w;}; vector<edge> e[N]; int d[N], vis[N]; priority_queue<pair<int,int>> q; bool prim(int s){ for(int i=0;i<=n;i++) d[i]=inf; d[s]=0; q.push({0,s}); while(q.size()){ int u=q.top().second; q.pop(); if(vis[u])continue; vis[u]=1; ans+=d[u]; cnt++; for(auto ed : e[u]){ int v=ed.v, w=ed.w; if(d[v]>w){ d[v]=w; q.push({-d[v],v}); } } } return cnt==n; }
|
Kruskal算法
适用于稀疏图,时间复杂度 O(mlogm)。
核心思想:从小到大挑不多余的边。
C++ 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <bits/stdc++.h> using namespace std;
const int N=200006; int n, m; int ans=0; struct edge{ int u,v,w; bool operator<(const edge &t)const {return w < t.w;} }e[N]; struct DSU { vector<int> f, siz; DSU() {} DSU(int n) { init(n); } void init(int n) { f.resize(n); std::iota(f.begin(), f.end(), 0); siz.assign(n, 1); } int find(int x) { while (x != f[x]) { x = f[x] = f[f[x]]; } return x; } bool same(int x, int y) { return find(x) == find(y); } bool merge(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; } siz[x] += siz[y]; f[y] = x; return true; } int size(int x) { return siz[find(x)]; } }; bool kruskal(){ sort(e+1,e+m+1); DSU dsu(n+1); int cnt=0; for(int i=1; i<=m; i++){ int x=(e[i].u); int y=(e[i].v); if(!dsu.same(x,y)) { dsu.merge(x,y); ans+=e[i].w; cnt++; } } return cnt==n-1; } int main(){ cin>>n>>m; for(int i=1; i<=m; i++) cin>>e[i].u>>e[i].v>>e[i].w; if(!kruskal()) puts("impossible"); else printf("%d\n",ans); return 0; }
|