数据结构4 并查集
- 查找的时候才更新的时候
- 合并的时候不更新
1 #include <iostream> 2 using namespace std; 3 #define N 100 4 int father[N]; 5 int n, m; 6 7 void init(){ 8 for(int i=1; i<=n; i++) 9 father[i] = i; 10 } 11 12 //查找 13 int Find(int x){ 14 if(x != father[x]) 15 father[x] = Find(father[x]); 16 return father[x]; // 一直要找到 x = father[x] 返回 17 } 18 19 20 // 合并 21 void Union(int x, int y){ 22 int a, b; 23 a = Find(x); 24 b = Find(y); 25 if(a != b) 26 father[b] = a; // 这边是随便给的,没有影响 27 } 28 29 int main(){ 30 int x, u, v, sum=0; 31 cout << "input n and m:" << endl; 32 cin >> n >> m; 33 init(); 34 cout << "input u and v" << endl; 35 for(int i=1; i<=m; i++){ 36 cin >> u >> v; 37 Union(u, v); 38 } 39 40 for(int i=1; i<=n; i++){ 41 Find(i); // 每次查找的时候更新数组 42 cout << father[i] << " "; 43 if(father[i]==i) 44 sum++; 45 } 46 cout << endl; 47 cout << "sum=" << sum << endl; 48 return 0; 49 }
测试数据:
10 9
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
每个节点都执行一次find,来完成路径压缩。
使用并查集改进Kruskal
先对边排序,然后使用并查集选边
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int N=100; 6 int father[N]; 7 int n, m; // 节点数,边数 8 9 struct Edge{ // kruskal对边进行排序 10 int u, v, w; 11 }e[N*N]; 12 // 有向图 n(n-1)/2 无向图 n(n-1) 13 14 bool cmp(Edge x, Edge y){ 15 return x.w < y.w; 16 } 17 18 void Init(int n){ // 节点从1到n 19 for(int i=1; i<=n; i++) 20 father[i] = i; 21 } 22 23 int Find(int x){ 24 if(x != father[x]) 25 father[x] = Find(father[x]); // 调用它父亲的集合号 26 return father[x]; 27 } 28 bool Union(int x, int y){ 29 int a = Find(x); 30 int b = Find(y); 31 if(a==b) return 0; 32 33 if(a > b){ // 小的赋值给大的集合号 34 father[a] = b; 35 }else{ 36 father[b] = a; 37 } 38 return true; 39 } 40 41 int Kruskal(int n){ 42 int ans = 0; 43 for(int i=0; i<m; i++){ 44 if(Union(e[i].u, e[i].v)){ 45 ans += e[i].w; 46 n--; 47 if(n == 1) // 我们要选n-1条边 48 return ans; 49 } 50 } 51 return 0; 52 } 53 int main(){ 54 cout << "输入结点数n和边数m:" << endl; 55 cin >> n >> m; 56 Init(n); 57 cout << "输入结点u,v和边权w:" << endl; 58 for(int i=0; i<m; i++) 59 cin >> e[i].u >> e[i].v >> e[i].w; 60 sort(e, e+m, cmp); 61 int ans = Kruskal(n); 62 cout << "最小的化费是:" << ans << endl; 63 int sum = 0; 64 for(int i=1; i<=n; i++){ 65 cout << father[i] << " "; 66 if(father[i] == i) 67 sum++; 68 } 69 cout << endl; 70 cout << "sum = " << sum << endl; 71 return 0; 72 }
7 12
1 2 23
1 6 28
1 7 36
2 3 20
2 7 1
3 4 15
3 7 4
4 5 3
4 7 9
5 6 16
5 7 16
6 7 25