这两个题目都要设一个数组表示当前元素和根结点的关系,当合并和查找时,由于根结点改变,所以当前元素和根结点的关系也要改变
poj 1182
题目大意:三种动物A,B,C,关系是A吃B,B吃C,C吃A ,给出一些判断,根据题意找出假话的总数
代码:
#include<iostream>
using namespace std;
int r[50010],parent[50010]; //r[]表示当前元素和根节点的关系,在这个题目里是吃与被吃的关系
void makeSet(int n){
int i;
for(i = 1;i <= n;i++){
parent[i] = i;
r[i] = 0;
}
}
int findSet(int x){
if(x != parent[x]){
int temp = parent[x];
parent[x] = findSet(parent[x]);
r[x] = (r[x]+r[temp])%3; //列举数据 推导公式
}
return parent[x];
}
void Union(int ra,int rb,int a,int b,int d){
parent[rb] = ra;
r[rb] = (r[a]-r[b]+2+d)%3;//同上
}
int main(){
int n,k,count = 0;
scanf("%d%d",&n,&k);
makeSet(n);
while(k--){
int a,b,d;
scanf("%d%d%d",&d,&a,&b);
if(a > n||b > n||(d == 2&&a == b)){
count++;
continue;
}
int ra = findSet(a);
int rb = findSet(b);
if(ra == rb){ //在一个集合中说明关系能判断
if(d == 1&&r[a] != r[b])
count++;
else if(d == 2&&r[a] != (r[b]+2)%3)
count++;
}
else
Union(ra,rb,a,b,d); //如果关系能判断 就放入集合中
}
printf("%d/n",count);
return 0;
}
poj 1988
题目大意:一些积木,标号为1到N,M a b 表示把a所在的那一列整体移动到b的上面,C a 则输出a的下面有多少积木
代码:
#include<iostream>
using namespace std;
#define N 30010
int parent[N],num[N],r[N];//r[]表示当前元素和根节点的关系 在这个题目里是深度
void makeSet(int n){
int i;
for(i = 1;i <= n;i++){
parent[i] = i;
num[i] = 1;
r[i] = 0;
}
}
int findSet(int x){
if(x != parent[x]){
int temp = parent[x];
parent[x] = findSet(parent[x]);
r[x] += r[temp];
}
return parent[x];
}
void Union(int a,int b){
int ra = findSet(a);
int rb = findSet(b);
parent[rb] = ra;
r[rb] = num[ra];
num[ra] += num[rb];
}
int main(){
int n;
char ch;
int a,b;
int ra,rb;
while(scanf("%d",&n) != EOF){
makeSet(N);
while(n--){
getchar();
scanf("%c",&ch);
if(ch == 'M'){
scanf("%d%d",&a,&b);
ra = findSet(a);
rb = findSet(b);
if(ra != rb)
Union(a,b);
}
else if(ch == 'C'){
scanf("%d",&a);
ra = findSet(a);
printf("%d/n",num[ra]-r[a]-1);
}
}
}
return 0;
}
类似的并查集基础题还有 poj 1703 2492 2236 1308