--------------------------------挑战编程部分-----------------------------------
并查集:
常用于查询元素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; }