--------------------------------挑战编程部分-----------------------------------
并查集:
常用于查询元素a和元素b是否属于同一组
合并元素a和元素b所在的组
基本代码:【摘自挑战程序】
int par[MAX_X]; //父亲
int rank[MAX_X]; //树的高度
//初始化
void init(int n){
for(int i=0;i<n;i++){
par[i]=i;
rank[i]=0;
}
}
//查询树的根
int find(int x){
if(par[x]==x){
return x;
}
else{
return par[x]=find(par[x]);
}
}
//合并x和y所属的集合
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
if(rank[x]<rank[y]){
par[x]=y;
}else{
par[y]=x;
if(rank[x]==rank[y]) rank[x]++;
}
}
//判断是否属于同一个集合
bool same(int x,int y){
return find(x)==find(y);
}
POJ1182食物链
书中介绍的主要解决方法是:
(i-A表示i属于种类A)
对每只队伍创建3个元素,分别属于A,B,C类。以下标N相隔
种类1 :x和y同属于同一类,分别合并x-A,y-A x-B,y-B x-C,y-C,
种类2 :x吃y…………………分别合并x-A,y-B x-B,y-C x-C,y-A,
注意在合并之前要先判断是否满足会矛盾。
【种类1检查x-A和y-B或者x-A和y-C是否属于同一组】
【种类2检查x-A和y-A或者x-A和y-C是否同一组】
#include <cstdio>
#define MAXN 50001
int par[3*MAXN],rank[3*MAXN];
//上方基本代码
//-----------------华丽丽模板分割线
int main(){
int n,k,tot=0;
int type,x,X,y,Y;
scanf("%d%d",&n,&k);
init(3*n);
for(int i=0;i<k;i++){
scanf("%d%d%d",&type,&X,&Y);
x=X-1,y=Y-1;
if(x<0||x>=n||y<0||y>=n){
tot++;
continue;
}
if(type==1){
if(same(x,y+n)||same(x,y+2*n)){
tot++;
}
else{
unite(x,y);
unite(x+n,y+n);
unite(x+2*n,y+2*n);
}
}
else{
if(same(x,y)||same(x,y+2*n)){
tot++;
}else{
unite(x,y+n);
unite(x+n,y+2*n);
unite(x+2*n,y);
}
}
}
printf("%d\n",tot);
return 0;
}