wenbao与并查集

 并查集:

1 int Find(int x){
2     if(T[x] == -1) return x;
3     int xx = T[x];
4     T[x] = Find(xx);
5     sum[x] += sum[xx];
6     return T[x];
7 }

http://poj.org/problem?id=1456

题意: 有N件商品,知道了商品的价值和销售的最后期限,只要在最后日期之前销售处,就能得到相应的利润,并且销售该商品需要1天时间,求出最大利润。

暴力做法:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <queue>
 4 #include <string.h>
 5 #include <algorithm>
 6 using namespace std;
 7 struct Node{
 8     int x, y;
 9 }T[10009];
10 int cmp(Node a, Node b){
11     if(a.x == b.x) return a.y > b.y;
12     return a.x > b.x;
13 }
14 bool vis[10009];
15 int main(){
16     int n, sum;
17     while(~scanf("%d", &n)){
18         sum = 0;
19         for(int i = 0; i < n; i++){
20             scanf("%d%d", &T[i].x, &T[i].y);
21         }
22         sort(T, T+n, cmp);
23         memset(vis, false, sizeof(vis));
24         for(int i = 0; i < n; i++){
25             for(int j = T[i].y; j >= 1; j--){
26                 if(!vis[j]){
27                     vis[j] = true;
28                     sum += T[i].x;
29                     break;
30                 }
31             }
32         }
33         printf("%d
", sum);
34     }
35     return 0;
36 }

并查集:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <queue>
 4 #include <string.h>
 5 #include <algorithm>
 6 using namespace std;
 7 const int maxn = 10009;
 8 struct Node{
 9     int x, y;
10 }T[maxn];
11 int cmp(Node a, Node b){
12     if(a.x == b.x) return a.y > b.y;
13     return a.x > b.x;
14 }
15 int TT[maxn];
16 int Find(int x){
17     return TT[x] == x ? x : TT[x] = Find(TT[x]);
18 }
19 int main(){
20     int n;
21     while(~scanf("%d", &n)){
22         int sum = 0;
23         for(int i = 0; i < n; i++){
24             scanf("%d%d", &T[i].x, &T[i].y);
25         }
26         sort(T, T+n, cmp);
27         for(int i = 0; i < maxn; i++){
28             TT[i] = i;
29         }
30         for(int i = 0; i < n; i++){
31             int xx = Find(T[i].y);
32             if(xx > 0){
33                 sum += T[i].x;
34                 TT[xx] = xx-1;
35             }
36         }
37         printf("%d
", sum);
38     }
39     return 0;
40 }

使用并查集后快的不是一点半点(快了一倍多)

总结:并查集牛!!!!!!!!!


 带权并查集:

1 T[yy] = xx;
2 sum[yy] = sum[x] + z - sum[y];
3 
4 T[xx] = yy;
5 sum[xx] = sum[y] - z - sum[x];
6 
7 sum[yy] + sum[xx] == sum[x] + z - sum[y] + sum[y] - z - sum[x] == 0;


http://acm.hdu.edu.cn/showproblem.php?pid=3038

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 int T[200009], sum[200009];
 6 int Find(int x){
 7     if(T[x] == -1) return x;
 8     int xx = Find(T[x]);
 9     sum[x] += sum[T[x]];
10     return T[x] = xx;
11 }
12 int main(){
13     int n, m, x, y, z;
14     while(scanf("%d %d", &n, &m) == 2){
15         memset(T, -1, sizeof(T));
16         memset(sum, 0, sizeof(sum));
17         int num = 0;
18         for(int i = 1; i <= m; i++){
19             scanf("%d %d %d", &x, &y, &z);
20             x = x - 1;
21             int xx = Find(x), yy = Find(y);
22             if(xx == yy){
23                 if(sum[y] - sum[x] != z)
24                     num ++;
25             }
26             else{
27                 T[xx] = yy;
28                 sum[xx] = sum[y] - z - sum[x];
29             }
30         }
31         printf("%d
", num);
32     }
33     return 0;
34 }

并查集经典题目:食物连

https://vjudge.net/contest/66964#problem/E

并查集的思想

  找到儿子与父亲、父亲与爷爷的关系进而t推出儿子与爷爷的关系(重点是向量关系图

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4 const int maxn = 50009;
 5 int T[maxn], re[maxn];
 6 int Find(int x){
 7     if(T[x] == x) return x;
 8     int xx = T[x];
 9     T[x] = Find(xx);
10     re[x] = (re[x] + re[xx] + 3) %3;
11     return T[x];
12 }
13 int main(){
14     int n, m, num = 0;
15     scanf("%d %d", &n, &m);
16     for(int i = 0; i <= n; i++){
17         T[i] = i, re[i] = 0;
18     }
19     for(int i = 0; i < m; i++){
20         int d, x, y;
21         scanf("%d %d %d", &d, &x, &y);
22         if(x > n || y > n){
23             num ++;
24             continue;
25         }
26         int xx = Find(x), yy = Find(y);
27         if(xx == yy){
28             if(d == 1 && re[x] != re[y]){
29                 num ++;
30             }else if(d == 2 &&(re[x] == re[y] || (re[y] - re[x] + 3) %3 == 2)){
31                 num ++;
32             }
33         }else{
34             T[yy] = xx;
35             re[yy] = (3 - re[y] + d - 1 + re[x] + 3) %3;
36         }
37     }
38     printf("%d
", num);
39     return 0;
40 }

 唉!!!!!越陷越深,,,,并查集怎么这么难!!


带权并查集加dp(要死了)

https://vjudge.net/contest/66964#problem/F

判断好人坏人;

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <vector>
 6 using namespace std;
 7 const int maxn = 700;
 8 int T[maxn], re[maxn], a[maxn][2], dp[maxn][maxn/2], fa[maxn][maxn/2];
 9 bool vis[maxn];
10 vector<int> v[maxn][2];
11 void init(int x){
12     for(int i = 0; i <=x; i++){
13         T[i] = i, re[i] = 0;
14         v[i][0].clear();
15         v[i][1].clear();
16         a[i][0] = a[i][1] = 0;
17     }
18 }
19 int Find(int x){
20     if(T[x] == x) return x;
21     int xx = T[x];
22     T[x] = Find(xx);
23     re[x] = (re[x] ^ re[xx]);
24     return T[x];
25 }
26 int main(){
27     int t, n, m, num, x, y;
28     char str[5];
29     while(scanf("%d%d%d", &t, &n, &m)){
30         if(t == 0 && n == 0 && m== 0) break;
31         int sum = n + m;
32         init(sum);
33         for(int i = 0; i < t; i++){
34             scanf("%d%d%s", &x, &y, &str);
35             int xx = Find(x), yy = Find(y);
36             if(xx != yy){
37                 if(str[0] == 'y') num = 0;
38                 else num = 1;
39                 T[xx] = yy;
40                 re[xx] = (re[x] ^ num ^ re[y]);
41             }
42         }
43         memset(vis, false, sizeof(vis));
44         num = 1;
45         for(int i = 1; i <= sum; i++) if(!vis[i]){
46             int xx = Find(i);
47             for(int j = i; j <= sum; j++)if(!vis[j] && xx == Find(j)){
48                 v[num][re[j]].push_back(j);
49                 a[num][re[j]] ++;
50                 vis[j] = true;
51             }
52             num ++;
53         }
54         memset(dp, 0, sizeof(dp));
55         dp[0][0] = 1;
56         for(int i = 1; i < num; i++){
57             for(int j = n; j >= 0; j--){
58                 if(j - a[i][0] >= 0 && dp[i-1][j-a[i][0]]){
59                     dp[i][j] += dp[i-1][j-a[i][0]];
60                     fa[i][j] = j - a[i][0];
61                 }
62                 if(j - a[i][1] >= 0 && dp[i-1][j-a[i][1]]){
63                     dp[i][j] += dp[i-1][j-a[i][1]];
64                     fa[i][j] = j - a[i][1];
65                 }
66             }
67         }
68         if(dp[num-1][n] != 1){
69             puts("no");
70         }else{
71             //cout<<num<<endl;
72             int b[maxn], num2 = 0;
73             for(int i = num-1; i >= 1; i--){
74                 int tem = n - fa[i][n];
75                 //cout<<i<<"******"<<n<<"****"<<tem<<endl;
76                 if(tem == a[i][0]){
77                     for(int j = 0; j < a[i][0]; j++){
78                         b[num2++] = v[i][0][j];
79                     }
80                 }else{
81                     for(int j = 0; j < a[i][1]; j++){
82                         b[num2++] = v[i][1][j];
83                     }
84                 }
85                 n = fa[i][n];
86             }
87             sort(b, b+num2);
88             for(int i = 0; i < num2; i++){
89                 printf("%d
", b[i]);
90             }
91             puts("end");
92         }
93     }
94     return 0;
95 }

http://poj.org/problem?id=1733

告诉你区间内奇偶数的个数,求第一个说假话的人。。。。。。

暴力带权并查集:

 1 #include <iostream>
 2 #include <map>
 3 #include <stdio.h>
 4 using namespace std;
 5 map<int, int> T;
 6 map<int, int> sum;
 7 int Find(int x){
 8     if(T[x] == 0) return x;
 9     int xx = T[x];
10     T[x] = Find(xx);
11     sum[x] = (sum[x] ^ sum[xx]);
12     return T[x];
13 }
14 int main(){
15     int n, t, x, y, a;
16     char str[5];
17     scanf("%d", &n);
18     scanf("%d", &t);
19     for(int i = 1; i <= t; i++){
20         scanf("%d%d%s", &x, &y, str);
21         if(str[0] == 'e') a = 0;
22         else a = 1;
23         x = x - 1;
24         int xx = Find(x), yy = Find(y);
25         if(xx != yy){
26             T[xx] = yy;
27             sum[xx] = (sum[x]^sum[y]^a);
28         }else{
29             if(sum[x]^sum[y] != a){
30                 printf("%d
", i-1);
31                 return 0;
32             }
33         }
34     }
35     printf("%d
", t);
36     return 0;
37 }

带权并查集加离散化:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <stdio.h>
 4 using namespace std;
 5 const int maxn = 5005;
 6 int T[maxn*2], sum[maxn*2], a[maxn*2];
 7 int n, t, b, num = 0, len;
 8 struct Node{
 9     int x, y;
10     char str[5];
11 }TT[maxn];
12 int Bin(int x){
13     int l = 0, r = len - 1, mid;
14     while(l <= r){
15         mid = (l + r) >> 1;
16         if(a[mid] == x) return mid;
17         if(a[mid] > x) r = mid;
18         else l = mid + 1;
19     }
20 }
21 int Find(int x){
22     if(T[x] == x) return x;
23     int xx = T[x];
24     T[x] = Find(xx);
25     sum[x] = (sum[x] ^ sum[xx]);
26     return T[x];
27 }
28 int main(){
29     scanf("%d", &n);
30     scanf("%d", &t);
31     for(int i = 0; i < t; i++){
32         scanf("%d%d%s", &TT[i].x, &TT[i].y, TT[i].str);
33         TT[i].x = TT[i].x - 1;
34         a[num++] = TT[i].x, a[num++] = TT[i].y;
35     }
36     sort(a, a+num);
37     len = unique(a, a+num) - a;
38     for(int i = 0; i <= len; i++){
39         T[i] = i, sum[i] = 0;
40     }
41     for(int i = 0; i < t; i++){
42         int xx = Bin(TT[i].x), yy = Bin(TT[i].y);
43         int xxx = Find(xx), yyy = Find(yy);
44         if(TT[i].str[0] == 'e') b = 0;
45         else b = 1;
46         if(xxx != yyy){
47             T[xxx] = yyy;
48             sum[xxx] = (sum[xx]^sum[yy]^b);
49         }else{
50             if(sum[xx]^sum[yy] != b){
51                 printf("%d
", i);
52                 return 0;
53             }
54         }
55     }
56     printf("%d
", t);
57     return 0;
58 }

离散化后速度快了两倍还多。。。。。厉害了。。。。


只有不断学习才能进步!

原文地址:https://www.cnblogs.com/wenbao/p/6142543.html