题目连接: POJ 1182
题目主要是得考虑找一个元素当这个集合的祖先,然后将其他两两动物之间的身份转变到对祖先的身份即可,这里用到一个向量转换相对身份,其实定义是可以改变的,一旦改变身份转换公式将改变。这道题做了我好长时间啊!!!
这里粘上一个人家的解题报告,给爱学习的你: 关于食物链的详解
// POJ 1182 食物链 并查集
//测试数据(右缩进的为假话):
//5 10
//2 1 3
//1 2 1
//2 4 1
//2 3 4
//2 4 5
// 2 3 2
// 1 4 3
// 1 4 5
//1 1 5
// 1 3 5
//
//假设:
// 2 2 --相对位置
// A -> B -> C -> A -> B -> C -> A
// 这样可以推出矛盾。
//
//定义为:
// 0——同类;
// 1——食物;吃父
// 2——天敌。被吃
// 4
// ./ `\ //食物链
//5,2,1 -> 3
//动物编号:2->1->3->5 // father[x] = find(father[x]); 递归调用 压缩路径
//父节点: 1 3 5 5 // rank[x] = (rank[x] + rank[temp]) % 3 当前的相对的 + 父节点的相对的
//相对的: 0 1 2 0 // return father[x];
// 1 3
// 吃 被
// 3 5
// 吃
#include <stdio.h>
#include <string.h>
const int MAXA = 50010;
int father[MAXA],sp[MAXA]; // sp special value
void init(int n){
memset(sp,0,sizeof(sp));
for (int i = 1; i <= n; i++) // 初始每个动物都以自己为父节点,所以关系为0同类
father[i] = i;
}
int find (int x){
if(x == father[x]) return x;
int temp = father[x];
father[x] = find(father[x]); // 递归 更新他爹
sp[x] = (sp[x] + sp[temp]) % 3; // 压缩更新他爹
return father[x]; // 只要返回它的爹 就可以了
}
void combination(int a,int b,int k){ // a b 关系为 k (this k is cut by 1) we should comb their root
int ra = father[a];
int rb = father[b];
father[ra] = rb; // make rb is the father of ra (把a的祖先接到b祖先上面)
sp[ra] = (k + sp[b] - sp[a] + 3) % 3;
}
int main(){
// freopen("in.txt","r",stdin);
int N,K;
int D,X,Y;
int fsum = 0; // 假话的数量
scanf("%d%d",&N,&K); // 只有一组测试数据
init(N);
for (int i = 1 ; i <= K; i++){
scanf("%d%d%d",&D,&X,&Y);
if ( (D==2 && X==Y )||( X>N || Y>N ) ){ // the last two rules
// printf("%d %d %d\n",D,X,Y);
fsum++;
}else{
int rx = find(X);
int ry = find(Y);
if (rx == ry){ // if they are in same set ,judge the relationship
if(sp[X] != (D - 1 + sp[Y] ) % 3){
// printf("%d %d %d\n",D,X,Y);
fsum++;
}
}else{ // different set ,(combination)fusion
combination(X,Y,D-1);
}
}
}
printf("%d\n",fsum);
return 0;
}