zoukankan      html  css  js  c++  java
  • uva 10158 War

    并查集经典题目,详细写一下吧

    题意:虽然比较长,但是题意还是比较好懂的。如果a和b是朋友,b和c是朋友,那么a和c是朋友。如果a和b是敌人,c和b是敌人,那么a和c要成为朋友

    操作1和2是假设(或者说试图建立某种关系),如果能成立不用输出,并且保持这种关系,如果这种假设(关系)与之前已经存在的关系是冲突的,那么输出-1,并且要保持原来的关系,放弃当前这个失败的。操作3和4是判断,即根据当前已知的关系,判断某两个人之间的关系是否成立,成立输出1,不成立或者无法确定就输出0

    1 a b  即试图让a和b成为朋友

    唯一不成立是:a在b的敌对集合中(那么同时b一定在a的敌对集合中)
    a和b有共同敌人,成立
    a和b至少有一个没有敌人,成立
    a和b都有敌人,但是敌人不同,也成立,不过要记得合并他们的敌人成为朋友

    2 a b 即试图让a和b成为敌人

    唯一不成立是:a和b在同一个集合
    成立后要修改一些关系:a和b成了敌人,那么b归到a的敌对集合中,a归到b的敌对集合中

    所以我们要用p数组来记录元素i处于那个集合(同集合的人都是朋友),还需要一个数组q去记录元素i的对立集合

    其实我的代码写得不是太好,感觉有点罗嗦,但是想不到再怎么精简了

    另外在查询祖先的时候,有压缩路径和没有压缩路径时间相差好大(0.048和0.580)

    AC后找的一个博客,觉得他这样写挺好,比我的好理解多了,向他学习学习,哈哈,不过时间上貌似比我的慢,这就有点慢理解了,不过怎么说都好我还是推崇他的写法

    http://hi.baidu.com/arosliu/item/d2933609055565354bc4a365

    #include <cstdio>
    #include <cstring>
    #define N 10010
    int p[N],q[N],m[N];
    int n,a,b,pa,pb,qa,qb;
    
    int find(int x)
    { return x==p[x]?x:p[x]=find(p[x]); }
    void fun1()
    {
        if(pa==qb && pb==qa)
            printf("-1\n");
        else
        {
            if(qa==-1 && qb==-1)
                p[pa]=pb;
            else if(qa==-1)
                p[pa]=pb;
            else if(qb==-1)
                p[pb]=pa;
            else
            { p[pa]=pb; p[qa]=qb; }
        }
        return ;
    }
    void fun2()
    {
        if(pa==pb)
            printf("-1\n");
        else
        {
            q[pa]=pb;
            q[pb]=pa;
            if(qa!=-1)
                p[qa]=pb;
            if(qb!=-1)
                p[qb]=pa;
        }
        return ;
    }
    void fun3()
    {
        if(pa==pb)
            printf("1\n");
        else 
            printf("0\n");
        return ;
    }
    void fun4()
    {
        if(pa==qb && pb==qa)
            printf("1\n");
        else
            printf("0\n");
        return ;
    }
    int main()
    {
        int c,a,b;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        { p[i]=i; m[i]=0; q[i]=-1;}
    
        while(scanf("%d%d%d",&c,&a,&b))
        {
            if(!c && !a && !b) break;
            pa=find(a);  //a元素所在集合是pa
            pb=find(b);  //b元素所在集合是pb
            qa=q[pa];   if(qa!=-1)qa=find(qa); //集合pa的对立集合是qa
            qb=q[pb];   if(qb!=-1)qb=find(qb); //集合pb的对立集合是qb
            
            if(c==1)  //建立朋友关系
                fun1();
            else if(c==2) //建立敌对关系
                fun2();
            else if(c==3) //判断朋友关系
                fun3();
            else          //判断敌对关系
                fun4(); 
        }
        return 0;
    }
  • 相关阅读:
    keepass
    gpg
    Wireshark实践
    ssh
    namp
    第十二周
    第十一周
    第十周总结
    第九周学习总结
    编程语言
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2818731.html
Copyright © 2011-2022 走看看