[poj1703]Find them, Catch them(种类并查集)

题意:食物链的弱化版本

解题关键:种类并查集,注意向量的合成。

$rank$为1代表与父亲对立,$rank$为0代表与父亲同类。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
#define M 100005
int fa[M],rank1[M];
int find1(int x){
    if(x==fa[x]) return x;
    int tmp=fa[x];
    fa[x]=find1(tmp);
    rank1[x]=(rank1[x]+rank1[tmp])%2;
    return fa[x];
}
void unite(int x,int y){
    int t=find1(x);
    int t1=find1(y);
    if(t!=t1){//合并的时候需要用到向量的合成和差
        fa[t1]=t;
        rank1[t1]=(1-rank1[y]+rank1[x])%2;
    }
}
char ch[10];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++){
            fa[i]=i;
            rank1[i]=0;
        }
        for(int i=0;i<m;i++){
            int tmp,tmp1;
            scanf("%s%d%d",ch,&tmp,&tmp1);
            if(ch[0]==‘D‘) unite(tmp,tmp1);
            else{
                int x=find1(tmp);
                int y=find1(tmp1);
                if(x==y){//可以判断出关系
                    int r=(2-rank1[tmp]+rank1[tmp1])%2;
                    if(r==0) printf("In the same gang.\n");
                    else printf("In different gangs.\n");
                }
                else printf("Not sure yet.\n");
            }
        }
    }
    return 0;
}

法二:$fa$数组代表$i$属于$A$或$i$属于$B$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=100005;
int fa[maxn*2];
int find1(int x){
    int r=x;
    while(r!=fa[r])  r=fa[r];
    int i=x,j;
    while(i!=r){
        j=fa[i];
        fa[i]=r;
        i=j;
    }
    return r;
}

void unite(int x,int y){
    x=find1(x),y=find1(y);
    if(x!=y) fa[x]=y;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int N,M,x,y;
        char opt[10];
        scanf("%d%d",&N,&M);
        for(int i=0;i<=2*N;i++) fa[i]=i;
        while(M--){
            scanf("%s%d%d",opt,&x,&y);
            if(opt[0]==‘A‘){
                if(find1(x)==find1(y)) printf("In the same gang.\n");
                else if(find1(x)==find1(y+N)&&find1(x+N)==find1(y)) printf("In different gangs.\n");
                else printf("Not sure yet.\n");
            }
            else{
                unite(x,y+N);
                unite(x+N,y);
            }
        }
    }
    return 0;
}
时间: 2024-10-09 23:41:24

[poj1703]Find them, Catch them(种类并查集)的相关文章

poj1703 Find them,Catch them 【并查集】

做过一些的带权并查集,再来做所谓的"种类并查集",发现好像就顿悟了. 种类并查集与带权并查集实质上的差别并不大, 关键的区别就是种类并查集只是带权并查集再弄个%取余操作而已,然后余数就表示他属于哪个种类. 这题只有两个种类,也就是只有0和1两种, 对于两个不同的种类,那么之间的权值是相差1的,所以按照带权并查集的方法做加上1,然后取余2即可. #include<cstdio> const int N = 100005; int n, m, f[N], rank[N]; in

[POJ1703]Find them, Catch them(并查集)

传送门 1.开两个并查集 f[x] 表示 x 的同类 f[x + n] 表示 x 的敌人 ——代码 1 #include <cstdio> 2 #include <iostream> 3 #define N 200001 4 5 int T, n, m; 6 int f[N]; 7 8 inline int read() 9 { 10 int x = 0, f = 1; 11 char ch = getchar(); 12 for(; !isdigit(ch); ch = getc

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

题意:N个人,M条关系,A x y表示询问x和y是不是属于同一组,D x y表示x和y是不同组.输出每个询问后的结果. 分析: 1.所有的关系形成一个连通图,如果x和y可达,那两者关系是确定的,否则不能确定. 2.r[tmpy] = r[x] + r[y] + 1;可以更新连通块里祖先的标号. eg: 5 4 D 1 2 D 2 3 D 4 5-----到此为止形成两个连通块,标号如图所示(红笔) D 3 5 第四步,将3和5连边,因为以0为祖先,所以4的标号应当改变,可以发现改变后的r[4]

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 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, 即

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为天使: 思路:种类并查集+