POJ 1703--Find them, Catch them

来源:互联网 发布:智多星定额造价软件 编辑:程序博客网 时间:2024/05/19 09:47

题意:一个城市有两个犯罪团伙,给定两种输入,第一种输入表示a,b两个人不在同一个团伙,第二种输入询问a,b是否是同一个团伙,输出到上一个输入为止能知道的他们的关系。

题解:并查集的一种扩展应用,原始的并查集集合中元素代表他们属于同一种集合,本题可以用这种集合代表有关系的一种集合,而集合类元素之间的关系则可以通过他们分别与根节点的关系求得。

  1. 关系转移:设IsSame[a] = 0代表a与他的根节点fa[a]属于同一团伙,等于1代表a与根节点不属于同一团伙,则若fa[a] == fa[b],a,b之间的关系:IsSame[a] ^ IsSame[b],同样为0代表a,b属于同一团伙,为1代表a,b属于不同团伙。
  2. 路径压缩:并查集的一种优化,在搜索a的根节点时直接将路径中的点指向最终的根节点,同样关系表IsSame[a]也需要随着根节点变化而变化。
注意:题意要求每个团伙至少有一个人,则当输入为两个人时,不需要任何其他输入我们就已经知道两个人属于不同团伙。而三个以上人,当没有关系提示时,我们不知道他们的关系,而当一有关系输入时,题设的条件已经能满足了。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;class solve{private:    int N,M;    int* fa;    int* height;    char* IsSame;       //1表示点与根节点不同伙,0表示同伙    char c;    int a,b;public:    solve(int n,int m):N(n),M(m)    {        fa = new int[N+1];        height = new int[N+1];        IsSame = new char[N+1];        makeSet();        if(n == 2)      //每个犯罪团伙至少有一人        {            unionSet(1,2);        }        while(M--)        {            getchar();            c = getchar();            scanf("%d%d",&a,&b);            if(c == 'D')            {                unionSet(a,b);            }            else            {                if(findSet(a) == findSet(b))                {                    if(IsSame[a]^IsSame[b])                    {                        printf("In different gangs.\n");                    }                    else                    {                        printf("In the same gang.\n");                    }                }                else                {                    printf("Not sure yet.\n");                }            }        }        return ;    }    ~solve()    {        delete[] fa;        delete[] height;        delete[] IsSame;    }    int makeSet();    int findSet(int x);    int unionSet(int x,int y);};int solve::findSet(int x){    if(x == fa[x])        return x;    int tmpfa = fa[x];    fa[x] = findSet(fa[x]);    IsSame[x] ^= IsSame[tmpfa]; //关系表随着根节点变化而变化    return fa[x];}int solve::unionSet(int x,int y){    int rootX = findSet(x);    int rootY = findSet(y);    if(rootX != rootY)     //根节点不同则开始合并    {        if(height[rootX] > height[rootY])   //按树的深度大小进行合并        {            fa[rootY] = rootX;            IsSame[rootY] = IsSame[x]^IsSame[y]^1;      //因为输入的x,y关系为1,经过x,y求得rootX和rootY的关系        }        else        {            fa[rootX] = rootY;            IsSame[rootX] = IsSame[x]^IsSame[y]^1;            if(height[rootX] == height[rootY])                height[rootY]++;        }    }    return 0;}int solve::makeSet(){    memset(IsSame,0,sizeof(char)*(N+1));    //初始化所有人与自己同伙    memset(height,0,sizeof(int)*(N+1));    for(int i = 1;i <= N;i++)    {        fa[i] = i;      //初始化每个人和自己一组    }    return 0;}int main(){    int T;    int n,m;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        solve poj_1703(n,m);    }    return 0;}


0 0
原创粉丝点击