题解 并查集 POJ 1182
题意:三类动物A、B、C,A吃B,B吃C,C吃A。
给出K句话来描述N个动物(各属于A、B、C三类之一)之间的关系,格式及意义如
下:
1X Y:表示X与Y是同类;
2X Y:表示X吃Y。
K句话中有真话有假话,当一句话满足下列三条之一时,这句话就是假话,否则就是
真话。
1)当前的话与前面的某些真的话冲突,就是假话;
2)当前的话中X或Y比N大,就是假话;
3)当前的话表示X吃X,就是假话。
1)当前的话与前面的某些真的话冲突,就是假话;
2)当前的话中X或Y比N大,就是假话;
3)当前的话表示X吃X,就是假话。
求假话的总数。
做法:由于对每个动物的种类未知,我们用3个堆来表示一个动物,即一个动物可以由
三种形态,A,B,C;如果两个动物为同类,我们就把这两个动物的3个堆合并。如果
x吃y,我们就将x-a,y-b;x-b,y-c;x-c,y-a合并。其中1个动物的堆用x,x+n,x+2n
表示。
代码:
#include <iostream> #include <cstdio> using namespace std; const int MAX=50000; int par[3*MAX+50]; int Find(int a) { if(par[a]!=a) par[a]=Find(par[a]); return par[a]; } bool same(int x,int y) { return Find(x)==Find(y); } void merge(int a,int b) { int p1=Find(a); int p2=Find(b); if(p1==p2) return ; par[p2]=p1; } int main() { int n,m,ans=0; int a,b,c,i; scanf("%d%d",&n,&m); for(i=0;i<=3*n;i++) par[i]=i; for(i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); b=b-1;c=c-1; if(b>=n||c>=n||b<0||c<0){ans++;continue;} if(a==1) { if(same(b,c+n)||same(b,c+2*n)) ans++; else merge(b,c),merge(b+n,c+n),merge(b+2*n,c+2*n); } else if(a==2) { if(same(b,c)||same(c,b+n)) ans++; else merge(b,c+n),merge(b+n,c+2*n),merge(b+2*n,c); } } printf("%d\n",ans); return 0; }