zoukankan      html  css  js  c++  java
  • POJ食物链,并查集,包含种类的分部

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

    看了别人的技巧,最后自己才勉强写出:(摘自poj)

    kind[a]=0表示a与父节点属于同一类。kind[a]=1表示a吃父节点。kind[a]=2表示父节点吃a。 (后二种情况下的赋值可以改变,但对后续有点小影响)
    
    1.有一种关系b是a父节点,c是b父节点,  a与c的关系可以表示为 (kind[a]+kind[b])%3    (延续性,适用于多个节点的延续,如3个节点根据二次计算即可完成)
    
    2.b是a的父节点,表示为kind[a].  若父子节点相互反转,即a是b的父节点,kind[b]=(3-kind[a])%3  (反转性)
    
    根据延续性和反转性可计算任何两个节点之间的关系,以下是几个例子:
    
    现在讨论并查集中用到关系的3中情况:
    (i):find中的更新,x的父节点是y,y的父节点为根节点,将关系更新为x的父节点为根节点,表示为:kind[x]=(kind[x]+kind[y])%3;
    (ii)并查集中的合并。  假设x的父节点是xx  y的父节点是yy  x和y的关系为d。
    若将xx的父节点更新为yy,则 kind[xx]=kind[x]的反转(即xx的父节点为x)+d(x的父节点为y)+kind[y](y的父节点为yy),
    简化为kind[xx]=(3-kind[x]+d+kind[y])%3.
    (iii)并查集中判断x,y是否冲突
    x和y的父节点都为同一个根节点,知道kind[x],kind[y],d(表示x和y的关系)
      3-kind[x](x的反转,根节点->x)+d(x->y)+kind[y](y->根节点)  根据延续性这个式子表示为  根节点->根节点的关系  即 (3-kind[x]+d+kind[y])%3==0 (在最后的判断这边,我是通过根结点然后算出x,y的关系,然后跟题目给的进行判断变为((kind[x]-kind[y]+3)%3!=d-1));
    #include<stdio.h>//有正确关系的点都是同一个集合 
    int bin[50010],kind[50010],wa;//kind保存该结点跟父结点的关系,在压缩路径的修改中也变成它跟根结点的关系  
    int findx(int x)
    {
        int r;
        if(x==bin[x])
         return x;
        r=bin[x];//这里本来用的是另一种递归,但是那样已经把x的父节点换成根结点了,就没法进行正确运算了 
        bin[x]=findx(bin[x]);
        kind[x]=(kind[x]+kind[r])%3;//x->根结点,跟结点->y,向量思想,可传递性相加结果到3时正好是原来的点 
        return bin[x];//返回根结点 
    }
    void merge(int x,int y,int d)
    {
         int fx,fy;
         fx=findx(x);
         fy=findx(y);
         if(fx==fy)//如果根结点相同,就可以进行判断 
         {
            if((kind[x]-kind[y]+3)%3!=d-1)//判断关系,利用食物链中两点不是d的那一条边,就可以算出正确的d,之所以d要减一,是因为题目给的d跟我们设置的kind不同步 
             {
              wa++;
             }
            return ;
         }
         bin[fx]=fy;//如果根结点不同,说明是不同的集合,所以就要进行合并 
         kind[fx]=(2-kind[x]+d+kind[y])%3;//假设x的父节点是xx  y的父节点是yy  x和y的关系为d。若将xx的父节点更新为yy,则 kind[xx]=kind[x]的反转(即xx的父节点为x)+d(x的父节点为y)+kind[y](y的父节点为yy),简化为kind[xx]=(3-kind[x]+d+kind[y])%3
    
    }
    int main()
    {
        int i,n,k,t,d,x,y;
        scanf("%d%d",&n,&k);//题目只要一组数据而已 
           for(i=1;i<=n;i++)
             bin[i]=i,kind[i]=0;//
           wa=0;
           while(k--)
           {
              scanf("%d%d%d",&d,&x,&y);
              if(x>n||y>n||(d==2&&x==y)){wa++;continue;}
              if(d==1&&x==y)continue;//上面两种情况都是可以跳过的 
               merge(x,y,d);//不满足时进行判断,合并 
           }
              printf("%d
    ",wa);
        return 0;
    }
    View Code
  • 相关阅读:
    1038 Recover the Smallest Number (30分) sort-cmp妙用(用于使字符串序列最小)
    1033 To Fill or Not to Fill (25分)贪心(???)
    1030 Travel Plan (30分) dij模板题
    1020 Tree Traversals (25分)(树的构造:后序+中序->层序)
    1022 Digital Library (30分) hash模拟
    1018 Public Bike Management (30分)(Dijkstra路径保存fa[]+DFS路径搜索)
    1017 Queueing at Bank (25分)模拟:关于事务排队处理
    1014 Waiting in Line (30分)队列模拟题
    1010 Radix (25分)暴力猜数or二分猜数
    HDU 3032 multi-sg 打表找规律
  • 原文地址:https://www.cnblogs.com/huzhenbo113/p/3231291.html
Copyright © 2011-2022 走看看