本题主要算法并查集,一般解决集合合并,是否在同一集合,一个集合中的元素个数等问题。复杂一点的就是带偏移量的,本题和1182很像,但是这个是只有两种情况。下面有个优化的算法。但是不是太多。
//594MS
/*#include<iostream>
#define N 100010
using namespace std;
int n,f[N],rank[N];
int cal(int a)
{
int t=0;
while(f[a]!=-1)
{
t+=rank[a];
a=f[a];
}
return t;
}
int Find(int t)
{
while(f[t]!=-1)
t=f[t];
return t;
}
void Union(int a,int b)
{
int x,y;
x=Find(a);
y=Find(b);
if(cal(a)<cal(b))
{
f[x]=y;
rank[x]=(cal(a)-cal(b)+1)%2;
}
else
{
f[y]=x;
rank[y]=(cal(a)-cal(b)+1)%2;
}
}
int main()
{
int i,j,k,m,x,y;
char ch;
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&n,&m);
memset(f,-1,sizeof(f));
memset(rank,0,sizeof(rank));
while(m--)
{
getchar();
scanf("%c %d %d",&ch,&x,&y);
if(ch=='A')
{
if(Find(x)!=Find(y))
{
printf("Not sure yet./n");
}
else
{
if((cal(x)-cal(y))%2==0)
printf("In the same gang./n");
else
printf("In different gangs./n");
}
}
else if(ch=='D')
{
if(Find(x)!=Find(y))
Union(x,y);
}
}
}
return 0;
}*/
我优化了一下。
//391MS
#include<iostream>
#define N 100010
using namespace std;
int n,f[N],rank[N];
void Init()
{
for(int i=1;i<=n;i++)
{
f[i]=i;
rank[i]=0;
}
}
int Find(int x)
{
if(x==f[x])
return x;
int tmp=Find(f[x]);
rank[x]=(rank[x]+rank[f[x]])%2;//由于最终的根节点rank为0,所以不会改变偏移量,反而带偏移量下面的子节点就会相应改变
f[x]=tmp;
return f[x];
}
void Union(int a,int b)
{
int x,y;
x=Find(a);
y=Find(b);
f[x]=y;
rank[x]=(rank[a]+rank[b]+1)%2;//修改根存偏移量,在find的 时候依次更新子节点。
}
int main()
{
int k,m,x,y;
char ch;
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&n,&m);
Init();
while(m--)
{
getchar();
scanf("%c %d %d",&ch,&x,&y);
/* //时间没什么改变,如果改成下面的代码。
if(ch=='A')
{
if(Find(x)!=Find(y))
{
printf("Not sure yet./n");
}
else
{
if(rank[x]==rank[y])
printf("In the same gang./n");
else
printf("In different gangs./n");
}
}
else if(ch=='D')
{
if(Find(x)!=Find(y))
Union(x,y);
}*/
if(Find(x)!=Find(y))
{
if(ch=='A')
{
printf("Not sure yet./n");
continue;
}
else
{
Union(x,y);
}
}
else
{
if(ch=='A')
{
if(rank[x]==rank[y])
printf("In the same gang./n");
else
printf("In different gangs./n");
}
}
}
}
return 0;
}