• POJ 1182 (经典食物链 /并查集扩展)


    版权声明:Site:https://skyqinsc.github.io/ https://blog.csdn.net/u013986860/article/details/27126561
    (參考他人资料)

    向量偏移——由“食物链”引发的总结

    http://poj.org/problem?

    id=1182这道食物链题目是并查集的变型,非常久曾经做的一次是水过的。这次细致地研究了这“食物链”,无非就是运用向量偏移,从曾经节点与节点转化成向量与向量的关系。我们能够把矛盾的产生得益于向量偏移时的结果。

    直接引出向量偏移的运用。

     

    以下是POJ一位大牛这样理解的,本人稍有改动。

    对于集合里的随意两个元素a,b而言,它们之间必然存在着某种联系,由于并查集中的元素均是有联系的,否则也不会被合并到当前集合中。那么我们就把这2个元素之间的关系量转化为一个偏移量,以食物链的关系而言。最好还是如果

    a->b 偏移量0时 a和b同类

    a->b 偏移量1时 a吃b

    a->b 偏移量2时 a被b吃。也就是b吃a

    有了这些基础。我们就能够在并查集中完毕随意两个元素之间的关系转换了。

    最好还是继续如果。a的当前集合根节点aa,b的当前集合根节点bb。a->b的偏移值为d-1(题中给出的询问已知条件)


    (1)如果aa和bb不同样,那么我们把bb合并到aa上,而且更新delta[bb]值(delta[i]表示i的当前集合根节点到i的偏移量)

    此时 aa->bb = aa->a + a->b + b->bb。可能这一步就是所谓向量思维模式吧

    上式进一步转化为:aa->bb = (3-delta[a]+d-1+delta[b])%3 = delta[bb],(模3是保证偏移量取值始终在[0,2]间)


    以图示表示为:





    (2)如果aa和bb同样,那么我们就验证a->b之间的偏移量是否与题中给出的d-1一致

     此时 a->b = a->aa + aa->b = a->aa + bb->b,

    上式进一步转化为:a->b = (3+delta[a]-delta[b])%3。若一致则为真。否则为假。

     

    以图示表示为:



     



    一般化总结:

    并查集的偏移向量属于并查集的变形。仅仅要适用于集合数目较少,或是固定的并查集类型。


    #include<iostream>
    #include<cstdio>
    #define maxn 50001
    using namespace std;
    
    int uset[maxn],rel[maxn];
    
    int find_uset(int x)
    {
        if(uset[x]!=x)
        {
            int k=uset[x];                  //先写
            uset[x]=find_uset(uset[x]);               //注意上下两处。由于递归调用循序的原因。
            rel[x]=(rel[k]+rel[x])%3;       //后写,
        }
        return uset[x];
    }
    
    int make_uset(int x,int y,int d)
    {
        int ux,uy;
        if((ux=find_uset(x))==(uy=find_uset(y)))
        {
            if((3+rel[x]-rel[y])%3!=(d-1))
                return 1;
            return 0;
        }
        else
        {
            uset[ux]=uy;
            rel[ux]=(3-rel[x]+d-1+rel[y])%3;
            return 0;
        }
    }
    
    
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
    
            int d,x,y,cnt=0;
            for(int i=1;i<=n;i++)
            {
                uset[i]=i;
                rel[i]=0;
            }
            for(int i=0;i<k;i++)
            {
                scanf("%d%d%d",&d,&x,&y);
                if(x>n||y>n||(d==2&&x==y))
                    cnt++;
                else if(make_uset(x,y,d))
                    cnt++;
            }
    
            printf("%d
    ",cnt);
    
    
    
        return 0;
    }
    


  • 相关阅读:
    CDN使用心得
    IIS6.0实现SSL安全加密
    从print css谈样式表的媒介(media)属性
    ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持
    “同名Cookie”的分析
    周末部门游玩顺德碧桂园度假村
    Linux特殊文件权限
    周末部门游玩广州长隆欢乐世界
    开个博客
    iOS TableView数据绑定的原则
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10790879.html
  • Copyright © 2020-2023  润新知