模板:最小生成树(MST)
https://www.luogu.org/problemnew/show/P3366
Kruskal算法 O(E*logE)
1. 所有的边从小到大排序
2. 初始状态下每个结点都是独立的集合
3. 枚举每一条边e
4. 如果边的两个端点u、 v属两个不同的集合,
把这条边加入MST, 否则跳过。
• 排序
• 贪心选择
• 并查集
用并查集优化后的总时间复杂度为(mlogm+ma(n)),a(n)是一次并查集的复杂度
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 struct Edge{ 6 int u, v, w; 7 }edge[200005]; 8 int f[5005], n, m, ans, eu, ev, cnt; 9 inline bool cmp(Edge a,Edge b){ 10 return a.w<b.w; 11 } 12 inline int find(int x){ 13 while(x!=f[x]) x=f[x]=f[f[x]]; 14 return x; 15 } 16 int main(){ 17 scanf("%d%d",&n,&m); 18 for(int i=1; i<=n; i++) f[i]=i; 19 for(int i=0; i<m; i++) 20 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); 21 sort(edge, edge+m, cmp); 22 for(int i=0; i<m; i++){ 23 eu=find(edge[i].u); 24 ev=find(edge[i].v); 25 if(eu==ev) continue; 26 ans+=edge[i].w; 27 f[ev]=eu; 28 cnt++; 29 if(cnt==n-1) break; 30 } 31 printf("%d",ans); 32 return 0; 33 }
Prim算法 O(N^2)
• 加点法, 每次选择代价最小的边对应的点,
加入到最小生成树中。
• 算法从某一个顶点s开始, 逐渐长大覆盖整
个连通网的所有顶点。
1. 图顶点集合为V; 初始集合u={s},v=V-u
2. 在两个集合u,v能够组成的边中, 选择一条
代价最小的边(u0,v0), 加入到最小生成树
中, 并把v0并入到集合u中。
3. 重复上述步骤, 直到最小生成树有n-1条边
或者n个顶点为止。
此处使用堆优化的的prim,每次选取最小值的时间复杂度为O(logm),总时间复杂度为O((n+m)logm).
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef pair <int,int> pii; 7 int k, n, m, cnt, sum,x, y, z; 8 int h[5005], dis[5005], vis[5005]; 9 struct Edge{ 10 int v, w, next;//边的右端点, 边权, 下一条边的编号 11 }e[400005]; 12 void add(int u,int v,int w){ 13 e[++k].v=v; 14 e[k].w=w; 15 e[k].next=h[u]; 16 h[u]=k; 17 } 18 priority_queue <pii,vector<pii>,greater<pii> > q;//第一维数值,第二维节点编号 19 void prim(){ 20 dis[1]=0; 21 q.push(make_pair(0,1)); 22 while(!q.empty() && cnt<n){ 23 int d=q.top().first, u=q.top().second; 24 q.pop(); 25 if(vis[u]) continue; 26 cnt++; 27 sum+=d; 28 vis[u]=1; 29 for(int i=h[u]; i!=-1; i=e[i].next) 30 if(e[i].w<dis[e[i].v]){ 31 dis[e[i].v]=e[i].w; 32 q.push(make_pair(dis[e[i].v],e[i].v)); 33 } 34 } 35 } 36 int main(){ 37 memset(dis,0x3f,sizeof(dis)); 38 memset(h,-1,sizeof(h)); 39 scanf("%d%d",&n,&m); 40 for(int i=1; i<=m; i++){ 41 scanf("%d%d%d",&x,&y,&z); 42 add(x,y,z); 43 add(y,x,z); 44 } 45 prim(); 46 if(cnt==n) printf("%d",sum); 47 else printf("orz"); 48 return 0; 49 }
"Hello World!"