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

    题目
    很经典的并查集题目
    反集做法:开三倍的数组,分别是吃x的和x吃的。

    #include <cstdio>
    #include <iostream>
    #include <cmath> 
    using namespace std;
    const int MAXN=200000;
    int f1[MAXN];
    int find(int x)//找爸+路径压缩
    {
        if(f1[x]==x) return x;
        return f1[x]=find(f1[x]);
    } 
    int main()
    {
        int n,m;
        int ans=0;
    
        scanf("%d%d",&n,&m);
    
        for(int i=1;i<=3*n;i++)
         f1[i]=i;//三倍集合
    
        for(int i=1;i<=m;i++)
        {
            int x,y,c;
    
            scanf("%d%d%d",&c,&x,&y);
    
            if(x>n||y>n||(x==y&&c==2)) 
            {
                ans++;
                continue;//特判
            }
    
            int fx=find(x);
            int fy=find(y);
    
            if(c==1)
            {
               if(fx==fy)    continue;
                if(fx==find(y+n)||fx==find(y+2*n)||fy==find(x+2*n)||fy==find(x+n))
                {
                    ans++;    continue;
                }        
            f1[find(x)]=find(y);//x的同类是y
            f1[find(x+n)]=find(y+n);//x+n的同类是y+n
            f1[find(x+2*n)]=find(y+2*n);//x+2n的同类是y+2n
            }
            else
            {
                if(fx==fy||fx==find(y+2*n)||fy==find(x+n))
                {
                    ans++;    continue;
                }
                f1[fx]=find(y+n);//fx即使吃y的动物的同类
                f1[fy]=find(x+2*n);//fy即使被x吃动物的同类
                f1[find(x+n)]=find(y+2*n);//x吃y,y吃z,那么z就吃x0.
            }
        }
    
        printf("%d",ans);
    
        return 0;
    }

    带权并查集的方法
    front数组是这个点到根节点的关系,因为只有三种动物且存在x吃y,y吃z那么z就吃x的关系,所以用0表示同类,1表示x吃y,2表示y吃z。
    !(图片)注意有个关键就是当我们知道x与祖先x1的关系,y与祖先y1的关系,x与y的关系时,求x1与y1的关系时,使用矢量计算:
    x1->x->y->y1 计算

    所以front[x1]=(-front[x]+front[y]+c-1+3)%3//防止出负数

    #include <cstdio>
    #include <iostream>
    #include <cmath> 
    using namespace std;
    int f1[999999],front[999999];
    int find(int x)
    {
        if(x==f1[x])
            return f1[x];
        int y=find(f1[x]);
            front[x]=(front[x]+front[f1[x]])%3;//计算与根节点的距离
        return f1[x]=y;
    }
    int main()
    {
        int n,m;
        int ans=0;
    
        scanf("%d%d",&n,&m);
    
        for(int i=1;i<=n;i++)
         f1[i]=i;
    
        for(int i=1;i<=m;i++)
        {
            int x,y,c;
    
            scanf("%d%d%d",&c,&x,&y);
    
            if(x>n||y>n||(x==y&&c==2)) //特判
            {
                ans++;
                continue;
            }
    
            int fx=find(x);
            int fy=find(y);
    
            if(fx==fy)//共同祖先,判断真话假话。
            {
                if((front[x]-front[y]+3)%3!=c-1) ans++;//出现矛盾假话++
            }
            else//不是共同祖先,默认真话,建立关系。
            {
                f1[fx]=fy;
                front[fx]=(-front[x]+c-1+front[y]+3)%3;//计算fx与fy的距离
            }
        }
    
        printf("%d",ans);
    
        return 0;
    }
  • 相关阅读:
    spring
    ajax
    jquary
    Java web 部分
    长跑马拉松
    面试的标准
    数据预处理——剔除异常值,平滑,归一化
    概率分布
    养生
    平滑的作用
  • 原文地址:https://www.cnblogs.com/ht008/p/6819833.html
Copyright © 2011-2022 走看看