zoukankan      html  css  js  c++  java
  • POJ 1182 食物链 带权并查集

    今天一定彻底弄懂 带权并查集

     好吧这题我还是不懂,,,烦躁

    现在基本上知道了吧,不过不清楚公式是怎样推出来的,如果要我再写一遍的话,估计会写很多个判断

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <fstream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <deque>
     7 #include <vector>
     8 #include <queue>
     9 #include <string>
    10 #include <cstring>
    11 //#include <unordered_map>
    12 #include <map>
    13 #include <stack>
    14 #include <set>
    15 #define LL long long
    16 #define INF 0x3f3f3f3f
    17 #define OPEN_FILE
    18 #define MAXN 50005
    19 using namespace std;
    20 int n, k;
    21 int father[MAXN];
    22 int ranK[MAXN];
    23 //rank[x]表示x 与 father[x] 的关系,0 是同类,1 是 x 吃 father[x], 2 是 father[x] 吃 x
    24 int find(int x){
    25     if (x == father[x]) return x;
    26     int y = father[x];
    27     father[x] = find(father[x]);
    28     ranK[x] = (ranK[x] + ranK[y]) % 3;
    29     //rank[x]=1,rank[y]=1,表示x吃路径压缩前的的father[x]
    30     //压缩前的father[x]吃压缩后的father[x],那么就是压缩后的father[x]吃x
    31     //所以rank[x]更新为2
    32     //rank[x] = 1, rank[y] = 1 ====> rank[x] = 2
    33     //rank[x] = 1, rank[y] = 2 ====> rank[x] = 0
    34     //rank[x] = 2, rank[y] = 1 ====> rank[x] = 0
    35     //rank[x] = 0, rank[y] = 1 ====> rank[x] = 1
    36     //rank[x] = 1, rank[y] = 0 ====> rank[x] = 1
    37     //rank[x] = 2, rank[x] = 2 ====> rank[x] = 1
    38     return father[x];
    39 }
    40 void union_set(int x, int y, int z){
    41     int a = father[x], b = father[y];
    42     father[a] = b;
    43     ranK[a] = (z + ranK[y] - ranK[x] + 3) % 3;
    44     //这里仅仅是更新了father[x]的rank值, 并没有更新其他的子节点
    45     //因为每次查询时都调用了find函数,在路径压缩的回溯过程中就会将其他节点的rank值更新
    46     //如果公式看不过来的话,那就有下面这几种情况
    47     //rank[x] = 1, rank[y] = 1, z = 1 ====> rank[a] = 1
    48     //rank[x] = 0, rank[y] = 1, z = 1 ====> rank[a] = 2
    49     //因为情况比较多,就不一一列举了,但是很好奇这个公式是怎样想出来的
    50     //看到别人的博客中提到向量?
    51 }
    52 int main()
    53 {
    54 #ifdef OPEN_FILE
    55     freopen("in.txt", "r", stdin);
    56     //freopen("out.txt", "w", stdout);
    57 #endif // OPEN_FILE
    58     scanf("%d%d", &n, &k);
    59     for (int i = 1; i <= n; i++){
    60         father[i] = i;
    61     }
    62     memset(ranK, 0, sizeof(ranK));
    63     int x, y, z;
    64     int cnt = 0;
    65     for (int i = 1; i <= k; i++){
    66         scanf("%d%d%d", &z, &x, &y);
    67         if (x > n || y > n){
    68             cnt++;
    69             continue;
    70         }
    71         if (x == y && z == 2){
    72             cnt++;
    73             continue;
    74         }
    75         if (x == y) continue;
    76         int a = find(x), b = find(y);
    77         if (a == b && ranK[x] != (z - 1 + ranK[y]) % 3){
    78             //如果father[x]!=father[y],那这两个还不属于同一个集合,谈不上假话了
    79             //属于同一个集合,就有下面几种情况可以保证是真话
    80             //z - 1 = 1, rank[y] = 2, rank[x] = 0 给的条件是x吃y,而y被他们的祖先吃,那只有x和father[y]是同类才可能是真话了
    81             //z - 1 = 1, rank[y] = 0, rank[x] = 1
    82             //z - 1 = 1, rank[y] = 1, rank[x] = 2
    83             //z - 1 = 0, rank[y] = 0, rank[x] = 0
    84             //z - 1 = 0, rank[y] = 1, rank[x] = 1
    85             //z - 1 = 0, rank[y] = 2, rank[x] = 2
    86             cnt++;
    87         }
    88         if (a != b){
    89             //还不属于同一个集合的话就肯定是真话,那就把他们的关系加到集合中来
    90             union_set(x, y, z - 1);
    91         }
    92     }
    93     printf("%d
    ", cnt);
    94 }
  • 相关阅读:
    archlinux .bash_history
    Ubuntu环境下挂载新硬盘
    软碟通 UltraISO U启替代品 Win32DiskImager 无设备 无盘符 无u盘 无优盘 解决方案 之diskpart
    delphi Integer overflow
    MSBuild Tools offline
    delphi synedit免费的拼写检查器dll
    git 自定义命令行
    lua编译
    gcc ar
    Windows Subsystem for Linux (WSL)挂载移动硬盘U盘 卸载 c d 盘
  • 原文地址:https://www.cnblogs.com/macinchang/p/4694362.html
Copyright © 2011-2022 走看看