• poj 1182 食物链 夜


    http://poj.org/problem?id=1182

    并查集的灵活应用 

    代码:

    /*
    可以这样理解
    并查集是由很多树组成的,这些树不断的合并
    下面代码f[]仍然代表此节点所属的树根
    而d[]表示此点到父节点的差值,但是每次求fx()(树根)时,节点都更新指向树根
    假如比父节点大1 则此点可以吃掉父节点
    假如比父节点大2 则此点可以被父节点吃掉
    假如和父节点相等,则属于同类
    这里所指的大是针对当前节点对父节点而言的,2比1大1   0比2大1(循环)
    由于更新完都指向树根了,所以就有了相同的参照物
    根据不同的点和树根的关系,可以推算出一棵树任意两点之间的关系
    
    问题就在于如何维护树的合并,f[]还是按照原来的方法,d[]需要根据实际情况取余
    理解是注意自己画图
    -----见代码注释
    
    */
    #include<cstdio>
    
    using namespace std;
    const int N=50005;
    int f[N],d[N];
    int fx(int x)
    {
        if(f[x]!=x)
        {
            int tmp=f[x];
            f[x]=fx(f[x]);
            //更新到这来时,x的父节点已经更新完成 指向根节点
            //而且x的父节点和根节点直接的关系也更新完成
            //结下了要更新x节点 因为x节点已经也指向了根节点(通过给f[x]赋值)
            //所以要根据父节点tmp到根节点的关系和x节点到父节点的关系
            //推算出x节点到根节点的关系,下面的式子就是计算过程 注意对3取余
            d[x]=(d[x]+d[tmp])%3;
        }
        return f[x];
    }
    int main()
    {
        //freopen("data.in","r",stdin);
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i)
        {f[i]=i;d[i]=0;}//初始化d[i]=0 因为每个节点开始指向自己 和自己是同类
        int ans=0;
        while(m--)
        {
            int a,b,w,A,B;
            scanf("%d %d %d",&w,&a,&b);
            if(a>n||b>n||a<=0||b<=0)
            {++ans;continue;}
            A=fx(a);
            B=fx(b);
            //这时候通过 fx(a),fx(b) a和b都更新完成,d[a]和d[b]都表示和各自根节点(可能相同,可能不同)关系
            if(w==1)
            {
                if(A==B)//假如 a和b 属于同一颗树
                {
                    if(d[a]!=d[b])//如果不是同一类,矛盾
                    ++ans;
                }else//假如不是同一颗树
                {
                    f[A]=B;//合并两棵树
                    //必须保证合并后d[a]和d[b]和树根B的关系一样
                    //那么就得满足d[a]+d[A]==d[b](%3) 所以。。。
                    d[A]=(d[b]+3-d[a])%3;
                }
            }else
            {
                if(A==B)//假如 a和b 属于同一颗树
                {
                    if((d[b]+1)%3!=d[a])//则d[a] 比 d[b] 大1 否则矛盾
                    ++ans;
                }else//假如不是同一颗树
                {
                    f[A]=B;//合并
                    //同样的原理 只不过要多加1 因为a吃b
                    d[A]=(d[b]+4-d[a])%3;
                }
            }
    
        }
        printf("%d\n",ans);
        return 0;
    }
    

      

     

  • 相关阅读:
    为什么new的普通数组用delete 和 delete[]都能正确释放
    虚幻4属性系统(反射)
    CFileDialog类的默认路径
    把单一元素的数组放在一个struct的尾端
    在UE4中使用SVN作为source control工具
    单精度浮点数和有效位数为什么是7位
    Valid Number--LeetCode
    归并排序
    堆排序
    直接选择排序
  • 原文地址:https://www.cnblogs.com/liulangye/p/2819802.html
Copyright © 2020-2023  润新知