赞
踩
- “并”和“查”是两个功能;“集”表示集合
- 解决一种把大量数据分块后查找某些数据是否是同一类的问题。
- 一般由find和join函数组成,这里咱们就详细讲一下课本P169kruscal算法里面的并查集(标号法)
思路:
- 先将所有边从小到大排序
- 遍历所有边依次选出不在同一集合的最小边加入最小生成树
- Kruskal证明
注: 判断是否在同一集合就用 “并查集”.
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5 + 10; int n, m, maxv = 0, ans;//n:点的个数;m:边的条数;maxv:最大点;ans:最小生成树的值 int parent[N];// 每个点所属的集合 struct Edge//存每条边的信息 { int head;//边的起点 int tail;//边的终点 int w;//边的权值 }edge[N]; bool cmp(Edge a, Edge b)//排序规则:按照权值w从小到大排序 { return a.w < b.w; } void Kruscal() { sort(edge, edge + m, cmp);//排序 for(int i = 1; i <= maxv; i ++) parent[i] = i;//开始每个点的父亲初始为自己 for(int i = 0; i < m; i ++)//遍历排序后的每条边 { int pos1 = edge[i].head;// pos1:边的始点 int pos2 = edge[i].tail;// pos2:边的终点 if(parent[pos1] != parent[pos2])// 当pos1与 pos2不在同一个集合时 { ans += edge[i].w;//将该条边加入树中 printf("加入%d到%d之间权值为%d的边!\n", edge[i].head , edge[i].tail, edge[i].w); //将大的标号更新为小的标号 int maxx = max(parent[pos1], parent[pos2]), minn = min(parent[pos1], parent[pos2]); for(int j = 1; j <= maxv; j ++) if(parent[j] == maxx) parent[j] = minn; puts("此时个点的标号变为:"); for(int j = 1; j <= maxv; j ++) printf("%d的标号为:%d\n", j, parent[j]); } } printf("最小生成树权值为:%d\n", ans); } int main() { cin >> n >> m; for(int i = 0; i < m; i ++) { int u, v, w; maxv = max(maxv,max(u, v)); cin >> u >> v >> w; edge[i] = {u, v, w}; } Kruscal(); return 0; } /* 测试数据: 6 10 1 2 6 1 3 1 1 4 5 2 3 5 2 5 3 3 4 5 3 5 6 3 6 4 4 6 2 5 6 6 */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。