poj 1182食物链解题报告
题目链接:http://poj.org/problem?id=1182
经典,好好看好好学。
这道题是很经典的并查集问题,当然,这道题也有着不同的解法,这里用带权并查集处理也可以,但是朴素做法也可以并且也容易理解一些;
首先这道题是构成的环形关系,所以说对于处理这类问题在约瑟夫中就已经可以看出了是取余或者扩容都可以
这里采用扩容,那么对于一个给出的生物关系a,
假定它是A,那a+n就是B,a+2*n就是C;
那在回到问题上,如果是同类的话,把同类a,b;
a+n,b+n;
a+2n,b+2n放在同一个集合里面就可以,如果不合条件的就是假话,
同样的,对于是捕食关系的生物来说,那么放到同一个集合里的就是存在捕食关系的,即:
a,b+n(A->B)
a+n,b+2n(B->C)
a+2n,b(B->C)
其余的,如果不和关系就是假话,
那问题就解决了:
按照这样的法则
- x,y不在N的范围内
- t=1对应同一类,但是之前的语句已经将x,y划分为两类了
- t=2对应捕食,但是之前的语句已经将x,y划分为不能捕食的关系
就可以解决这个问题了,
这个问题还是比较经典的,对于扩展并查集本身来讲是经典题目,带权并查集也可以有效的解决这个问题,思路开阔即可、
1 #include<iostream>//poj1182 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 const int num=1e5+10; 7 int s[num]; 8 int height[num]; 9 int n,m; 10 int ans; 11 void init_set() 12 { 13 for(register int i=1;i<=3*n;i++) 14 { 15 height[i]=0; 16 s[i]=i; 17 } 18 } 19 int find_set(int x) 20 { 21 if(x!=s[x]) 22 { 23 s[x]=find_set(s[x]); 24 } 25 return s[x]; 26 } 27 void union_set(int x,int y) 28 { 29 x=find_set(x); 30 y=find_set(y); 31 if(height[x]==height[y]) 32 { 33 height[x]++; 34 s[y]=x; 35 } 36 else 37 { 38 if(height[x]<height[y]) 39 { 40 s[x]=y; 41 } 42 else 43 { 44 s[y]=x; 45 } 46 } 47 } 48 bool same(int x,int y) 49 { 50 return find_set(x)==find_set(y); 51 } 52 int main() 53 { 54 cin>>n>>m; 55 init_set(); 56 for(register int i=1;i<=m;i++) 57 { 58 int t,x,y; 59 scanf("%d %d %d",&t,&x,&y); 60 if(x>n||y>n)//超出编号 61 { 62 ans++; 63 continue; 64 } 65 if(t==1) 66 { 67 if(same(x,y+n)||same(x,y+2*n))//同一类生物违背的情况 68 { 69 ans++; 70 } 71 else 72 { 73 union_set(x,y);//把同类生物放入同一集合 74 union_set(x+n,y+n); 75 union_set(x+2*n,y+2*n); 76 } 77 } 78 else 79 { 80 if(same(x,y)||same(x,y+2*n))//捕食关系生物违背的情况 81 { 82 ans++; 83 } 84 else 85 { 86 union_set(x,y+n);//捕食关系放入同一集合 87 union_set(x+n,y+2*n); 88 union_set(x+2*n,y); 89 } 90 } 91 } 92 printf("%d\n",ans); 93 return 0; 94 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16286032.html