zoukankan      html  css  js  c++  java
  • 三个种类的并查集——pku1182(中上难度)

    这道题目,理解了好久,其实只要把关系图画一下,有些概念自然就知道了……
    当然也使我明白了,并查集因为通过路径压缩后,一个节点的find()过程,最多需要2次递归,最多一次修改……这样题目就理解了……
    View Code
    #include <stdio.h>
    #define max 50000+5
    int f[max];
    int r[max];
    /*
    rank[x]表示father[x]与x的关系
    rank[x] == 0 表示father[x]与x是同类
    rank[x] == 1 表示x吃father[x]
    rank[x] == 2 表示father[x]吃x
    */
    void make_set(int x)
    {
    f[x]
    =-1;
    r[x]
    =0;
    }
    int find_set(int x)
    {

    if (f[x]==-1) return x;
    int t=f[x];
    f[x]
    =find_set(t);//路径压缩

    r[x]
    =(r[t]+r[x])%3;
    //important. 更新r[]数组中x与代表元素的相对关系。更新原因:
    //代表元素在union_set操作中被改变了。
    //至于这个式子的推得.可以枚举rx与p[x], p[x]与x的关系,然后观察得到。
    //更好的方法是向量运算。
    return f[x];
    }
    void union_set(int x,int y,int d)
    {
    int a=find_set(x);
    int b=find_set(y);
    f[a]
    =b;
    r[a]
    = (r[y] - r[x]+ 2 + d ) % 3;
    //同上。这两个关系的推得实际上是这道题的关键所在。
    }
    int main()
    {
    int n,k;
    int d,x,y,lie=0;

    scanf(
    "%d%d",&n,&k);
    for (int i=0;i<max;i++)
    make_set(i);
    while (k--)
    {
    int a,b;
    scanf(
    "%d%d%d",&d,&x,&y);
    if (d==2&&x==y) {lie++;continue;}
    if (x>n||y>n) {lie++;continue;}
    a
    =find_set(x);
    b
    =find_set(y);

    if (a==b)
    {
    if (d==1&&r[x]!=r[y])
    lie
    ++;
    else
    {
    if (d==2&&r[x]!=(r[y]+1)%3)
    lie
    ++;
    }
    }
    else
    union_set(x,y,d);
    }
    printf(
    "%d\n",lie);
    return 0;
    }
  • 相关阅读:
    8.图片切换
    6.节点的访问关系和操作
    4.京东狗
    3.关闭京东广告栏
    1.事件的拓展
    小飞鸟 小游戏
    网页特效(旋转木马轮播图)
    时间转换
    深入理解css3中的flex-grow、flex-shrink、flex-basis
    VUE 使用插件vue-clipboard2复制内容至剪切板(两种使用方法)
  • 原文地址:https://www.cnblogs.com/huhuuu/p/1966302.html
Copyright © 2011-2022 走看看