zoukankan      html  css  js  c++  java
  • 食物链

    【题目描述】

    动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A吃B,B吃C,C吃A。   

    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。   

    有人用两种说法对这N个动物所构成的食物链关系进行描述:   

    第一种说法是“1 X Y”,表示X和Y是同类。   

    第二种说法是“2 X Y”,表示X吃Y。   

    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

    (1) 当前的话与前面的某些真的话冲突,就是假话;   

    (2) 当前的话中X或Y比N大,就是假话;   

    (3) 当前的话表示X吃X,就是假话。   

    你的任务是根据给定的N(1<=N<=50,000)和K句话(0<=K<=100,000),输出假话的总数。

    【输入描述】

    第一行是两个整数N和K,以一个空格分隔。   

    以下K行每行是三个正整数D,X,Y,两数之间用一个空格隔开,其中 D 表示说法的种类。   

    若D=1,则表示X和Y是同类。   

    若D=2,则表示X吃Y。

    【输出描述】

    只有一个整数,表示假话的数目。

    【样例输入】

    100 7

    1 101 1

    2 1 2

    2 2 3

    2 3 3

    1 1 3

    2 3 1

    1 5 5

    【样例输出】

    3

    【数据范围及提示】

    对7句话的分析

    100 7

    1 101 1  假话

    2 1 2    真话

    2 2 3    真话

    2 3 3    假话

    1 1 3    假话

    2 3 1    真话

    1 5 5    真话

    源代码:
    
    #include<cstdio>
    int f[50001],i[50001]={0}; //f[]表示父亲指针,i[]存储权值。
    int N,K,ans(0);
    void Init() //初始化。
    {
        for (int a=1;a<=N;a++)
          f[a]=a;
    }
    int Find(int t) //路径压缩。
    {
        if (t!=f[t])
        {
            int T=Find(f[t]); //别小看递归,此递归直达根节点。
            i[t]=(i[t]+i[f[t]])%3; //与根节点的权值关系。
            f[t]=T;
        }
        return f[t];
    }
    int Merge(int x,int y,int Flag)
    {
        int t1=Find(x);
        int t2=Find(y);
        if (t1==t2)
        {
            if ((i[y]-i[x]+3)%3!=Flag) //同下,依据公式。
              return true;
            else
              return false;
        }
        f[t2]=t1; //连接根节点。
        i[t2]=(i[x]-i[y]+Flag+3)%3; //更新权值。
        return false;
    }
    int main()
    {
        scanf("%d%d",&N,&K);
        Init();
        for (int a=0;a<K;a++)
        {
            int D,X,Y;
            scanf("%d%d%d",&D,&X,&Y);
            if (X>N||Y>N||(X==Y&&D==2))
              ans++;
            else
              if (Merge(X,Y,D-1))
                ans++;
        }
        printf("%d",ans);
        return 0;
    }
    
    /*
        加权并查集:
            设关系(权值):
                0 ---- 此节点与其父节点为同类;
                1 ---- 此节点被其父节点捕食;
                2 ---- 此节点捕食其父节点。
            题中所述:
                1 X Y ---- X与Y为同类;
                2 X Y ---- X捕食Y。
            便有妙不可言之处:
                ①(D-1) <----> 关系(权值); 
                ②当 Father[i].Number = Father[Father[i].Number].Number 时,
                    有 Father[i].Sum = (Father[i].Sum+Father[Father[i]].Sum)%3(路径压缩)。
            集合合并:
                输入D X Y,为了合并,如何确定Father[X](根节点A)与Father[Y](根节点B)的关系呢?
                    ①(D-1) <----> 当X为Y父节点时,Y的Sum; 
                    ②(3-Father[Y].Sum) <----> 根据Y的Sum(相对于根节点B)逆推得到的B的Sum(相对于子节点Y);
                    ③衔接的过程为:先将Y连接到X上,再把B连接到X上,最终把B连接到A上;
                综上可得:
                    ①Father[B].Sum(相对于父节点X) = ((D-1)+(3-Father[Y].Sum))%3;
                    ②Father[B].Sum(相对于父节点A) = ((D-1)+(3-Father[Y].Sum)+Father[X].Sum)%3。
    */
  • 相关阅读:
    case when then用法
    查询后n条记录
    自定义函数
    字符函数
    数字运算符和函数
    时间日期函数
    mysql加密函数
    比较运算符和函数
    文件夹中的文件以目录的形式呈现
    错误提示:通过 Web 服务器的身份验证的用户无权打开文件系统上的文件
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5450019.html
Copyright © 2011-2022 走看看