zoukankan      html  css  js  c++  java
  • 并查集-食物链(向量偏移)

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

    食物链
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 44998   Accepted: 13122

    Description

    动物王国中有三类动物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),输出假话的总数。 

    Input

    第一行是两个整数N和K,以一个空格分隔。 
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
    若D=1,则表示X和Y是同类。 
    若D=2,则表示X吃Y。

    Output

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

    Sample Input

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    Sample Output

    3
    分析:该题是种类并查集,每个动物都属于A,B,C三类中的一类,始终满足A<-吃-B<-吃-C<-吃-A的关系;

    用两个数组即可,f[]表示祖先节点,mark[]表示每个节点的状态

    所以用0,1,2,三个数表示与祖先节点的关系:0表示与祖先同类,1表示被祖先吃,2表示吃祖先;

    举个例子就很清楚了

    设被吃者指向父节点即吃者

    112:

    A=1的祖先是1此时x=f[1]=1, mark[1]=0;

    B=2的祖先是2此时y=f[2]=2], mark[2]=0;

    因为12,所以f[y]=x即:f[2]=1; 2的状态比1

    所以mark[y]=(mark[a]+1-mark[b]+3)%3;(就是把当前的增量平移到祖先身上)

    ==>mark[1]=0;mark[2]=1;

    (2) 23

       A=2的祖先是1此时x=f[2]=1mark[2]=1;

       B=3的祖先是3此时y=f[3]=3;  mark[3]=0;

       f[y]=x;即:f[3]=1;

    所以mark[y]=(mark[a]+1-mark[b]+3)%3;

    ==>mark[3]=2;

    此时图形是:


    (3)同理还有45,56可构成下图:


    (4)此时加入35

    A=3,x=f[3]=1;mark[3]=2;

    B=5;y=f[5]=4;mark[5]=1;

    3的状态要比5的状态小1,所以看看要是把5集合加入到3的集合中,5的祖先平移 量是多少mark[y]=(mark[a]+1-mark[b]+3)%3,因为mark[y]在任何时候都是mark[y]=0;所以直接赋值就行了,此时:


    此时只是更新了祖先的mark值;

    当找5的时候务必会进行一次finde()函数:

    int finde(int x)

    {

        if(x!=f[x])

        {

            int t=f[x];

            f[x]=finde(f[x]);

            mark[x]=(mark[x]+mark[t])%3;

        }

        return f[x];

    }

    F[5]=1;mark[5]=0;

    同理要求6的话f[6]=1;mark[6]=1;



    可以看出mark值相同的动物是一类的;

    加入35是同类的话

    Mark[y]=(mark[a]-mark[b]+3)%3;

    Mark[4]=1;mark[5]=2;mark[6]=0;


    程序:

    #include"string.h"
    #include"stdio.h"
    #include"queue"
    #include"stack"
    #include"iostream"
    #include"math.h"
    #define M 60006
    #define inf 100000000
    using namespace std;
    int f[M],mark[M];
    int finde(int x)
    {
        if(x!=f[x])
        {
            int t=f[x];
            f[x]=finde(f[x]);
            mark[x]=(mark[x]+mark[t])%3;
        }
        return f[x];
    }
    void make(int a,int b)
    {
        int x=finde(a);
        int y=finde(b);
        if(x!=y)
        {
            f[y]=x;
            mark[y]=(3+mark[a]+1-mark[b])%3;
        }
    }
    void same(int a,int b)
    {
        int x=finde(a);
        int y=finde(b);
        if(x!=y)
        {
            f[y]=x;
            mark[y]=(3+mark[a]-mark[b])%3;
        }
    }
    int main()
    {
        int n,m,i;
        scanf("%d%d",&n,&m);
    
            for(i=1;i<=n;i++)
                f[i]=i;
            memset(mark,0,sizeof(mark));
            int wrong=0;
            while(m--)
            {
                int d,a,b;
                scanf("%d%d%d",&d,&a,&b);
                if(a>n||b>n||a<1||b<1)
                {
                    wrong++;
                    //printf("Wrong
    ");
                    continue;
                }
                int x=finde(a);
                int y=finde(b);
                if(d==1)
                {
                    if(x!=y)
                        same(a,b);
                    else
                    {
                        if(mark[a]!=mark[b])
                        {
                            //printf("Wrong
    ");
                            wrong++;
                        }
                    }
                }
                if(d==2)
                {
                    if(x!=y)
                        make(a,b);
                    else
                    {
                        if(mark[a]+1!=mark[b]&&mark[a]!=mark[b]+2)
                        {
                            //printf("Wrong
    ");
                            wrong++;
                        }
                    }
                }
            }
            printf("%d
    ",wrong);
    
        return 0;
    }



  • 相关阅读:
    Object中的线程等待和Condition
    synchronized锁和Lock锁
    手写二叉排序树(二叉查找树、二叉搜索树)
    JDK源码之ArrayList-Iterator
    JDK源码之ArrayList
    Integer&int,自动装箱&自动拆箱
    学习Zookeeper第一课
    Thumbnailator处理图片
    线程的停止和中断
    BigInteger和BigDecimal
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348174.html
Copyright © 2011-2022 走看看