这几道题都是POJ中入门级别的并查集题目……一一道来
http://blog.csdn.net/dellaserss/article/details/7724401这个写的特别好,基本上开完就能懂并查集的基本思想。
POJ1161 The Suspects
题意说是传染SARS其实就是找组织门派的……给出两个关系在一组的话,比较它们的find是否相等,相等不管了,不相等合并到一起并进行处理就好了……
Code:
#include
using namespace std;
int pre[30000];
int a[30001];
int find(int x)
{
if(pre[x]==x)
return x;
else
{
return find(pre[x]);
}
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0)break;
for(int i=0; i>k;
for(int j=1; j<=k; j++)
cin>>a[j];
for(int jj=2; jj<=k; jj++)
{
if(find(a[jj])!=find(a[1]))
{
int temp=find(a[jj]);
pre[temp]=a[1];
}
}
}
int total=0;
for(int i=0; i
题意:有两个帮派,各有一些成员,现在我们要区分它们的关系,在一个帮派,不在一个帮派或者不确定……
很容易想到并查集,但这道题目其实是一道种类并查集。我们不管要将所有的人放到一个中区,我们还需要记录每个点和find()(就是唯一的pre[x]==x的那个点,也就是文章中说的掌门)的关系,开了一个数组w,和他一个帮派记录0,不一个记录1。 种类并查集往往需要通过关系计算w,,w[b]=(w[x]+w[y]+1)%2;这个式子就是这道题的公式。
我们针对询问,两个x,y如果find(x)!=find(y)他们的关系还没有被确定。 反之比较w,如果w相等为一个帮派,反之为不同帮派的。
AC代码:
#include
#include
#include
using namespace std;
int pre[100001];
int w[100001];
int find(int x)
{
int temp;
if(pre[x]==x)return x;
else
{
temp=pre[x];
while(pre[temp]!=temp)
{
w[x]=(w[x]+w[temp])%2;
temp=pre[temp];
}
pre[x]=temp; //路径压缩
}
return temp;
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a!=b)
{
pre[b]=a;
w[b]=(w[x]+w[y]+1)%2;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(w,0,sizeof(w));
int n,m,t1,t2;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
w[i]=0;
pre[i]=i;
}
char c;
for(int i=1; i<=m; i++)
{ getchar();
scanf("%c %d %d",&c,&t1,&t2);
if(c=='A')
{
int x1=find(t1),x2=find(t2);
if(x1!=x2)
printf("Not sure yet.\n");
else
{
if(w[t1]==w[t2])
printf("In the same gang.\n");
else
printf("In different gangs.\n");
}
}
else
{
Union(t1,t2);
}
}
}
}
题目意思很简单,找不同宗教信仰……这题目没什么难度啦,大家练练手,不多说了。
AC code:
#include
#include
int pre[50001];
int rank[50001];
int num[50001];
int total;
using namespace std;
int find(int x)
{
if(pre[x]==x)return x;
else
return find(pre[x]);
}
void Union(int x,int y)
{
if(num[x]
非常经典的种类并查集。
和POJ1703很像,但是关键是有三种类型,公式可能比较难发现。思路还是把所有的不同类鱼放到一个关系中,在记录和首的关系……0同类,1吃他,2被吃。公式是关键。
Code:
#include
#include
using namespace std;
int pre[50001];
int rank[50001];
int sum;
int find(int x)
{ int temp;
if(pre[x]==x)return x;
else
{
temp=pre[x];
while(pre[temp]!=temp)
{
rank[x]=(rank[x]+rank[temp])%3;
temp=pre[temp];
}
pre[x]=temp; //路径压缩
}
return temp;
}
void Union(int x,int y,int c,int i)
{
int a=find(x);
int b=find(y);
if(a==b)
{
if((rank[y]-rank[x]+3)%3!=c-1)
{
sum++;
}
}
else
{
pre[b]=a;
rank[b]=(rank[x]-rank[y]+3+c-1)%3; //转化公式
}
}
int main()
{
int n,k;
scanf("%d %d",&n,&k);
sum=0;
int a,b,c;
for(int i=1; i<=n; i++)
{
pre[i]=i;
rank[i]=0;
}
for(int i=1; i<=k; i++)
{
scanf("%d %d %d",&c,&a,&b);
if(a>n||b>n)
{
sum++;
}
else if(a==b&&c==2)
{
sum++;
}
else
{
Union(a,b,c,i);
}
}
printf("%d\n",sum);
}