poj 1703 poj1182(并查集)

来源:互联网 发布:mac seesheer试色 编辑:程序博客网 时间:2024/06/05 06:43

poj1703: 题目大意:有n个人分别属于两个团伙,两种操作 D a b表示a b不在同一团伙,A a b表示询问a b是否在同一团伙
首先要对并查集的基本概念了解,fa[]代表每个元素的父亲是谁,rank[]数组代表的是树的深度,但是根据不同题意会有不同的意义,这个对理解题意很重要。

那么对与这道题,刚开始每个节点都是一棵树,各自的父亲是自己,后来合并,即每个犯罪人都是一个节点,两个人的关系就是一条线,从而逐渐形成一棵树。

这棵树的边相连的两个点是代表不是一个团伙。其实我理解的是深度相同的都属于同一门派,但是这里只有两个门派,所以根据敌人的敌人是朋友的原则,这里rank[]数组的处理就好理解了,所以深度只有0,1.(这种处理方式在下一题会有更好的解释)。


////可以把每个人看做一个点 每个关系看做一条边,rank[]本来表示树的深度,在这里表示点之间的权值,两点之间每条线权值为1,// rank[]依然是深度,表示该点到根节点的深度,如果两个点在同一个集合,并且深度一样,那么就是同一个帮派。#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;#define maxn 100005int n;int fa[maxn];int rank[maxn];void Init() //初始化{for(int i=0;i<=n;i++){fa[i]=i;rank[i]=0;}}int find(int x){if(fa[x]!=x){int father=find(fa[x]);rank[x]=(rank[x]+rank[fa[x]])%2;fa[x]=father;return fa[x];} return x;}void Union(int x,int y)//合并两个集合 相当于加一条边{int a=find(x);int b=find(y); //find 的时候依次更新rank[]fa[a]=b;rank[a]=(rank[x]+rank[y]+1)%2;}int main(){int cas;scanf("%d",&cas);while(cas--){int m,a,b,i;char ch[3];scanf("%d%d",&n,&m);        Init();for(i=1;i<=m;i++){scanf("%s%d%d",ch,&a,&b);if(ch[0]=='D'){Union(a,b);}else{if(n==2)printf("In different gangs.\n");else if(find(a)==find(b)){if(rank[a]==rank[b])printf("In the same gang.\n");elseprintf("In different gangs.\n");}elseprintf("Not sure yet.\n");}}}return 0;}
poj1182

题目大意:

食物链 关系有三种情况 rank[] 表示与父亲的关系 0 同类 1 吃父亲,2 被父亲吃
关于向量的问题,这里有牛人很好的说明。O(∩_∩)O哈哈~ 我也是站在巨巨的肩膀上\(^o^)/~
http://www.cnblogs.com/wuyiqi/archive/2011/08/24/come__in.html
另外这个题还WA了好多次,其一是要单组数据才能过,其二就是合并的时候父节点写反辣。。噗噗。。

//食物链 关系有三种情况 rank[] 表示与父亲的关系 0 同类 1 吃父亲,2 被父亲吃// 应该是和上一道提一样的 但总觉得有些不明白的地方//好多牛人啊。。向量 tx ty 分别为x y 与其的父亲的关系,已知 x->tx x->y y->ty// 求 tx->ty 因为两个合并时要fa[ty]=tx;// tx->ty = tx->x+x->y+y->ty// so:tx->ty=(-rank[x]+d-1+rank[y])%3;=(rank[y]-rank[x]+d-1)%3#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;int n;int fa[55555];int rank[55555];void Init(){    for(int i=1;i<=n;i++)    {        fa[i]=i;        rank[i]=0;    }}int find(int x){    if(fa[x]!=x)    {        int fath=find(fa[x]);        rank[x]=(rank[x]+rank[fa[x]])%3;        return fa[x]=fath; // 路径压缩 的时候rank[]如何修改呢?                    // fa[x]=ffa[x] x->tx tx->ttx so:x->ttx=(rank[x]+rank[fa[x]])%3;    }    return x;} int Union(int d,int x,int y){if(x>n || y>n)return 1;    if(d==1 && x==y)return 1;     int tx=find(x);    int ty=find(y);    if(tx==ty)    {        if((rank[y]-rank[x]+3)%3!=d){return 1; }        else return 0;    }    else    {        fa[ty]=tx; //这里不能写反了。。。         rank[ty]=(rank[x]-rank[y]+d+3)%3;        return 0;    }}int main(){//freopen("q.in","r",stdin);    int k,d,x,y,res,i;    scanf("%d%d",&n,&k)==2;    res=0;    Init();    for( i=1;i<=k;i++)    {        scanf("%d%d%d",&d,&x,&y);        if(Union(d-1,x,y))res++;    }    cout<<res<<endl;    }


0 0