poj1182食物链(种类并查集)

时间:2023-03-09 05:59:31
poj1182食物链(种类并查集)

http://poj.org/problem?id=1182

r[x] = 0 表示x和父亲是同类
r[x] = 1 表示x吃父亲
r[x] = 2 表示x被父亲吃
因为只存在三种动物,且三种动物构成了环形
所以动物之间的关系是可推导的。

如图:poj1182食物链(种类并查集)

c与a的关系为(r[b] + r[c])%3; b与父亲a的关系可为0,1,2      c与父亲b的关系为0,1,2 。每种取值时,自己在纸上推导一下,就能得到这个关系。

路径压缩的时候就要用到这个关系来修改r[c],

如何判断 D a b 是不是假话呢?   当fa == fb 时。说明动物a和b都在一个集合里。那么可以推导它们之间的关系

poj1182食物链(种类并查集)

我们已知两条黑线,我们要求得是红线2,即a与b的关系。  如果知道红线1,那么推导a和b的关系,那么就和上面那个图一样

红线1 = (3 - r[b])%3;  这个枚举一下r[b]的取值,然后推一下就知道了

所以如果  (r[a] + 3-r[b])%3==d-1  那么就是真话

如果fa!=fb。 那么就要合并两个集合

poj1182食物链(种类并查集)。道理和上面一样,先求红线1,然后求红线2,继而求出红线3.然后合并两个集合

 #include <stdio.h>
int father[],r[]; void init(int n)
{
for(int i=; i<=n; ++i)
{
father[i] = i;
r[i] = ;
}
} int find(int x)
{
if(x==father[x]) return father[x];
int t = find(father[x]);
r[x] = (r[father[x]] + r[x])%;
father[x] = t;
return father[x];
/*
路径压缩时关系的推导,r[father[x]] 是father[x]和根结点的关系,r[x]是x和father[x]的关系
*/
}
int main()
{
int n,k,i,d,x,y,ans,fx,fy;
scanf("%d%d",&n,&k);
{
ans = ;
init(n);
for(i=; i<k; ++i)
{
scanf("%d%d%d",&d,&x,&y);
if(x>n || y>n ||(d== && x==y)) ans++;
else
{
fx = find(x);
fy = find(y);
if(fx==fy)
{
if((r[x]+-r[y])%!=d-) ans++;
}
else
{
father[fx] = fy;
//r[fy] = (r[x]-r[y]+d-1+3)%3;
r[fx] = (d-+r[y]-r[x])%;
}
}
}
printf("%d\n",ans);
}
return ;
}