zoukankan      html  css  js  c++  java
  • 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 }

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


    只有不断学习才能进步!

  • 相关阅读:
    JSON Web令牌(JWT)
    CSRF跨站点请求伪造(Cross—Site Request Forgery)
    logging模块
    Django中使用Celery
    第一坑 先引入jQuery ./引入
    CSS 入门
    超大型文件传输方案 + socket + subprocess popen 远程执行系统命令
    MYSQL的执行计划 事务处理 和 跑路
    mysql 存储过程
    Django中CBV View的as_view()源码解析
  • 原文地址:https://www.cnblogs.com/wenbao/p/6142543.html
Copyright © 2011-2022 走看看