poj2492(种类并查集)

题目链接: http://poj.org/problem?id=2492

题意: 有t组测试数据, 对于每组数据,第一行n, m分别表示昆虫的数目和接下来m行x, y,

x, y表示教授判断x, y为异性, 问教授是否有错误判断,即存在x, y为同性;

这道题和poj1703类似, 不过更简单一点 (poj1703题解)

解法1: 我们可以用rank[x]记录x与其父亲节点的关系, rank[x]=0表同性, rank[x]=1表异性;

假设前面的教授判断都是正确的, 若后面存在与前面判断矛盾的数据,那么教授判断有误;

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 2010
 4 using namespace std;
 5
 6 int rank[MAXN], pre[MAXN]; //***rank[x]存储x与其父亲节点的关系
 7
 8 int find(int x){  //***递归压缩路径
 9     if(x!=pre[x]){
10         int px=find(pre[x]);
11         rank[x]=(rank[x]+rank[pre[x]])%2;  //***跟新rank[x]
12         pre[x]=px;
13     }
14     return pre[x];
15 }
16
17 int jion(int x, int y){
18     int px=find(x);
19     int py=find(y);
20     if(px==py){
21         if((rank[x]+rank[y])%2==0){ //**rank得出x, y的关系为同性,又由题意得出输入的x, y是异性, 矛盾
22             return 1;
23         }else{
24             return 0;
25         }
26     }else{
27         pre[py]=px; //**合并
28         rank[py]=(rank[x]+rank[y]+1)%2; //**更新rank[py]
29     }
30     return 0;
31 }
32
33 int main(void){
34     int t, m, n;
35     scanf("%d", &t);
36     for(int k=1; k<=t; k++){
37         scanf("%d%d", &n, &m);
38         for(int i=0; i<=n; i++){
39             pre[i]=i;
40             rank[i]=0;
41         }
42         int flag=0;
43         while(m--){
44             int x, y;
45             scanf("%d%d", &x, &y);
46             if(jion(x, y)){
47                 flag=1;
48             }
49         }
50         if(flag){
51             printf("Scenario #%d:\nSuspicious bugs found!\n\n", k);
52         }else{
53             printf("Scenario #%d:\nNo suspicious bugs found!\n\n", k);
54         }
55     }
56     return 0;
57 }

解法2:  并查集里面合并同一性别的昆虫, 用n+x表示与x性别相反的昆虫

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 2010
 4 using namespace std;
 5
 6 int pre[MAXN*2];
 7
 8 int find(int x){  //***递归压缩路径
 9     return x==pre[x]?pre[x]:pre[x]=find(pre[x]);
10 }
11
12 void jion(int x, int y){//**合并
13     int px=find(x);
14     int py=find(y);
15     if(px!=py){
16         pre[px]=py;
17     }
18 }
19
20 int main(void){
21     int t, m, n;
22     scanf("%d", &t);
23     for(int k=1; k<=t; k++){
24         scanf("%d%d", &n, &m);
25         for(int i=0; i<=2*n; i++){
26             pre[i]=i;
27         }
28         int flag=0;
29         while(m--){
30             int x, y;
31             scanf("%d%d", &x, &y);
32             if(find(x)==find(y)){
33                 flag=1;
34             }else{
35                 jion(x, y+n);
36                 jion(x+n, y);
37             }
38         }
39         if(flag){
40             printf("Scenario #%d:\nSuspicious bugs found!\n\n", k);
41         }else{
42             printf("Scenario #%d:\nNo suspicious bugs found!\n\n", k);
43         }
44     }
45     return 0;
46 }

解法3: 用vis数组标记, vis[x]存储与x性别不同的昆虫

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 2010
 4 using namespace std;
 5
 6 int pre[MAXN*2], vis[MAXN*2];
 7
 8 int find(int x){  //***递归压缩路径
 9     return x==pre[x]?pre[x]:pre[x]=find(pre[x]);
10 }
11
12 void jion(int x, int y){//***合并
13     int px=find(x);
14     int py=find(y);
15     if(px!=py){
16         pre[px]=py;
17     }
18 }
19
20 int main(void){
21     int t, m, n;
22     scanf("%d", &t);
23     for(int k=1; k<=t; k++){
24         scanf("%d%d", &n, &m);
25         for(int i=0; i<=2*n; i++){
26             pre[i]=i;
27             vis[i]=0;
28         }
29         int flag=0;
30         while(m--){
31             int x, y;
32             scanf("%d%d", &x, &y);
33             if(find(x)==find(y)){
34                 flag=1;
35             }else if(vis[x]+vis[y]==0){ //***如果之前x, y都没有出现
36                 vis[x]=y;
37                 vis[y]=x;
38             }else if(!vis[x]){ //***x没有出现
39                 vis[x]=y;
40                 jion(x, vis[y]);
41             }else if(!vis[y]){ //***y没有出现
42                 vis[y]=x;
43                 jion(y, vis[x]);
44             }else{ //***都出现过
45                 jion(x, vis[y]);
46                 jion(vis[x], y);
47             }
48         }
49         if(flag){
50             printf("Scenario #%d:\nSuspicious bugs found!\n\n", k);
51         }else{
52             printf("Scenario #%d:\nNo suspicious bugs found!\n\n", k);
53         }
54     }
55     return 0;
56 }
时间: 2024-12-11 10:58:22

poj2492(种类并查集)的相关文章

POJ-2492 A Bug&#39;s Life(种类并查集)

http://poj.org/problem?id=2492 题意: 给出一个T代表几组数据,给出一个n一个m,代表人的编号由1~n,m条命令,每条命令由两个数值组成,代表这两个人性别不同,问所有命令是否符合逻辑 两种写法: 第一种:带权并查集 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h&g

poj 2492 a bug&#39;s life 简单种类并查集

题意大致为找同性恋的虫子.... 这个比食物链要简单些.思路完全一致,利用取余操作实现关系之间的递推. 个人感觉利用向量,模和投影可能可以实现具有更加复杂关系的并查集. 1 #include<cstdio> 2 using namespace std; 3 const int MAXN=50010; 4 int fa[MAXN]; 5 int rel[MAXN]; // 0代表同类,1代表吃fa[i],2代表被吃 6 void _set(int n) 7 { 8 for(int i=1;i&l

POJ1182 食物链---(经典种类并查集)

题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69207   Accepted: 20462 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食

poj1733(种类并查集+离散化)

题目链接: http://poj.org/problem?id=1733 题意: 输入n表示有一个长度为n的0,1字符串, m表示接下来有m行输入, 接下来的m行输入中x, y, even表示第x到第y个字符中间1的个数为偶数个, x, y, odd表示第x到第y个字符中间1的个数为奇数个, 若m句话中第k+1是第一次与前面的话矛盾, 输出k; 思路: 若x, y之间1的个数为偶数个, 那么1~x 与1~y中1的个数同奇偶性, 反之则异奇偶性, 我们可以将其理解为若输入x, y, even, 即

POJ1703--Find them, Catch them(种类并查集)

Time Limit: 1000MSMemory Limit: 10000K Total Submissions: 32909Accepted: 10158 Description The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, t

poj 1182 食物链(种类并查集 ‘初心者’)

题目链接:http://poj.org/problem?id=1182 借着这题可以好好理解一下种类并查集,这题比较简单但挺经典的. 题意就不解释了,中问题. 关于种类并查集结局方法也是挺多的 1扩增倍数. 就是有几种关系就建立几倍数组,具体方法在这里不详细说了,这种方法有弊端 比较复杂而且内存消耗比较大如果关系比较多就容易爆掉. 2向量的方法. 这种方法要详细解说一下.这个方法好处都有啥.......(自行脑补后面的话) 这个方法的优点占用内存比较小而且比较简洁.只要找到关系就行. 下面就用方

poj1417(种类并查集+dp)

题目:http://poj.org/problem?id=1417 题意:输入三个数m, p, q 分别表示接下来的输入行数,天使数目,恶魔数目: 接下来m行输入形如x, y, ch,ch为yes表示x说y是天使,ch为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q):天使只说真话,恶魔只说假话: 如果不能确定所有天使的编号,输出no,若能确定,输出所有天使的编号,并且以end结尾: 注意:可能会有连续两行一样的输入:还有,若x==y,x为天使: 思路:种类并查集+

种类并查集

//http://acm.timus.ru/problem.aspx?space=1&num=1003//分析:树和递归最常用的思想是分治:并查集是一种合并树的数据结构:合并树或加入树节点时,我们只在意新建立的树边上相邻的两个树节点之间的关系,实际上树边只在意相邻两个树节点之间的关系//思路:可以讲一段连续区间的奇偶性表示成两个前缀和的奇偶性:将出现的离散的点用map离散化一下:将数量减少的点做一次种类并查集 1 #include"iostream" 2 #include&qu

HDU 3038 How Many Answers Are Wrong(种类并查集)

题目链接 食物链类似的题,主要是在于转化,a-b的和为s,转换为b比a-1大s.然后并查集存 此节点到根的差. 假如x的根为a,y的根为b: b - y = rank[y] a - x = rank[x] y - x = s 可以推出b - a = rank[y] - rank[x] + s; 并查集 延迟更新什么的,都忘了啊. 还有这题,如果是x--的话,记得更新0的根. #include <cstring> #include <cstdio> #include <stri