题意:一个城市有两个犯罪团伙,给定两种输入,第一种输入表示a,b两个人不在同一个团伙,第二种输入询问a,b是否是同一个团伙,输出到上一个输入为止能知道的他们的关系。
题解:并查集的一种扩展应用,原始的并查集集合中元素代表他们属于同一种集合,本题可以用这种集合代表有关系的一种集合,而集合类元素之间的关系则可以通过他们分别与根节点的关系求得。
- 关系转移:设IsSame[a] = 0代表a与他的根节点fa[a]属于同一团伙,等于1代表a与根节点不属于同一团伙,则若fa[a] == fa[b],a,b之间的关系:IsSame[a] ^ IsSame[b],同样为0代表a,b属于同一团伙,为1代表a,b属于不同团伙。
- 路径压缩:并查集的一种优化,在搜索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;
}


728

被折叠的 条评论
为什么被折叠?



