数据结构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

 

转载于:https://www.cnblogs.com/JCcodeblgos/p/11524696.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值