图论/数据结构-并查集

并查集知识点参考

主要应用的知识点:带权并查集的作用,如何维护带权并查集(本质是某个点沿多条能到根结点的路径时,这几条路径长度相等或在取模意义上相等)

题解

  • 数据结构:由题得,所有元素(动物)都是有相互的关系且关系之间具有传递性,因为有关系可以考虑并查集,而有传递性可以考虑带权并查集。并查集用根节点维护,并查集中每个元素传递性关系用到根结点距离的相对关系维护。那就假定与父节点距离为1的节点是吃父节点的,0是同类,2是被父节点吃的,相对距离即为距离取模3后的值。即并查集确定有无关系,带权的距离确定是什么关系。

  • 算法:对于每一对给定的关系,如果原先没有建立起关系,即原先没有在一个集合(图)中,那么由数学逻辑的知识可得,先去假定这对关系是正确的;如果这对关系已经在之前出现过,那么就判断这次的关系和之前的关系有没有矛盾,有矛盾就有一个谎话。

代码

#include 

using namespace std;

const int N = 5e4+5;
int p[N],d[N];//d代表某点到父节点的距离
int n,m;

int find(int x){
    if(x!=p[x]){
        int t=p[x];
        p[x]=find(p[x]);
        d[x]+=d[t];
    }
    
    return p[x];
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)p[i]=i;//初始化
    
    int res=0;//记录谎话个数
    while (m -- ){
        int a,x,y;
        cin>>a>>x>>y;
        int px=find(x),py=find(y);
        
        if(x>n||y>n)res++;//如果编号超出所给的动物编号数,直接判错
        else{//在给定编号内,不管给出1还是2的关系,都按以下顺序来解题。
            // 先判断是否已经在建立的图当中,如果在那么就可以判断是否为谎话,如果不在那么假定其不是谎话并加入图中
            if(a==1){
                if(px==py && (d[y]-d[x])%3)res++;//判断是否为谎话
                if(px!=py){//假定为真话,加入图中
                    p[px]=py;
                    d[px]=d[y]-d[x];
                }
            }
            else{
                if(px==py && (d[y]+1-d[x])%3)res++;//判断是否为谎话
                if(px!=py){//假定为真话,加入图中
                    p[px]=py;
                    d[px]=d[y]+1-d[x];
                }
            }
        }
    }
    
    cout<<res<<'\n';
    return 0;
}

你可能感兴趣的:(日杂,图论,数据结构,算法)