[并查集]团伙

题号:ZHOJ1258

思路:并查集。

给每个人建立一个“正集”(朋友)、一个“反集”(敌人),反集要么为空、要么指向一个正集,维护这两类集合,最后统计“正集”的个数。

 1 #include<cstdio>
 2 #include<cstring>
 3 const int N=1000;
 4 int ans;
 5 class UnionFindSet {
 6     private:
 7         int anc[N],anti[N];
 8     public:
 9         UnionFindSet(int n) {
10             for(int i=0;i<=n;i++) {
11                 anc[i]=i;
12                 anti[i]=0;
13             }
14         }
15         int Find(int x) {
16             return (x==anc[x])?x:(anc[x]=Find(anc[x]));
17         }
18         void Union(int op,int x,int y) {
19             if(op==1) {
20                 if(Find(y)==Find(x)) return;
21                 anc[Find(y)]=Find(x);
22             }
23             if(op==2) {
24                 if(anti[x]) Union(1,anti[x],y);
25                 if(anti[y]) Union(1,anti[y],x);
26                 if(!anti[x]) anti[x]=Find(y);
27                 if(!anti[y]) anti[y]=Find(x);
28             }
29         }
30         int Count(int n) {
31             bool vis[n+1];
32             memset(vis,0,sizeof vis);
33             for(int i=1;i<=n;i++) vis[Find(i)]=true;
34             int ans=0;
35             for(int i=1;i<=n;i++) if(vis[i]) ans++;
36             return ans;
37         }
38 };
39 int main() {
40     int n,m;
41     scanf("%d%d",&n,&m);
42     UnionFindSet s(n);
43     while(m--) {
44         int op,x,y;
45         scanf("%d%d%d",&op,&x,&y);
46         s.Union(op,x,y);
47     }
48     printf("%d\n",s.Count(n));
49     return 0;
50 }
时间: 2024-10-09 16:06:32

[并查集]团伙的相关文章

【并查集】团伙

[codevs2597] 团伙 时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两个强盗是同一团伙的条件是当且仅当他们是朋友.现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙. 输入描述 Input Description 输入文件gangs.in的第

【Luogu P2024&amp;P1892】食物链&amp;团伙(并查集拓展域)

Luogu P1892 Luogu P2024 这两道一眼看过去很容易发现可以用并查集来做--但是当我们仔细阅读题面后,会发现其实并没有那么简单. 我们知道并查集可以很轻松地维护具有传递性的信息,也就是"朋友的朋友就是我的朋友"这样的关系,但是普通的并查集并不能维护"敌人的敌人是朋友"这种关系. 这时候我们就要引入一种神奇的操作,将并查集扩大一倍,将增加的这一倍空间来维护节点i的敌人. 例如对于团伙这一题 if (c=='F') { merge(x,y); } el

BZOJ 1370: [Baltic2003]Gang团伙(luogu 1892)(种类并查集)

题面: bzoj题面有误,还是看luogu的吧 https://www.luogu.org/problemnew/show/P1892 题解: 种类并查集.. 因为有敌人的敌人是朋友这个条件,所以需要一个中转点.. 因此,将每个点拆成两个点,一个是朋友点,另一个是敌人点.当读到A与B是朋友时,就将A与B所对应的朋友点并集:当读到两个点是敌人的时候,就将A点所对应的敌人点与B所对应的朋友点并集,将A所对应的朋友点和B所对应的敌人点并集. 代码: #include<bits/stdc++.h> u

【并查集】Gym - 100923H - Por Costel and the Match

meciul.in / meciul.out Oberyn Martell and Gregor Clegane are dueling in a trial by combat. The fight is extremely important, as the life of Tyrion Lannister is on the line. Oberyn and Gregor are measuring their skill in combat the only way the two be

读书笔记 之 数据结构(并查集详解)(POJ1703)

<ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元素构成单元素集合,然后按照一定顺序将同属一组的集合合并,期间要反复查找每一个元素在哪个集合中.这类问题往往看似简单,但是数据量很大,因此容易造成TLE或MLE,也就是空间度和时间度极其复杂.因此在这里,我们引入一种抽象的特殊数据结构——并查集. 并查集:类似一个族谱,每个结点均有一个father[x]来表示x

并查集入门

我是看着<啊哈!算法>这本书完成并查集的入门,本想举出另外的栗子,奈何...书上的栗子已经很贴切了. 首先引入一个问题:已知有10个土匪,警方需要需要一点点顺藤摸瓜最后挖出他们各自背后的团伙一锅端,经过一段时间的侦查警方的得到了9条确切线索,分别能说明那两个土匪的归顺关系.那么请问此次行动总共要打掉几个团伙? 输入数据如下: 按照第一行输入人数n,线索数m,接下来的m行输入线索,每行线索如1 2代表1号和2号土匪是一伙的.现提供一组数据以供后续讲解和程序测试: <span style=&

并查集—解密犯罪团伙

警察想查清楚有几个犯罪团伙,搜集到了一些线索: 现在有10个强盗: 1号强盗与2号强盗是同伙: 3号强盗与4号强盗是同伙: 5号强盗与2号强盗是同伙: 4号强盗与6号强盗是同伙: 2号强盗与6号强盗是同伙: 8号强盗与7号强盗是同伙: 9号强盗与7号强盗是同伙: 1号强盗与6号强盗是同伙: 2号强盗与4号强盗是同伙: 强盗同伙的同伙也是同伙,请问一共有多少个独立的犯罪团伙? 基本思路: 1.一维数组f,表示10个强盗,值存储每个强盗的boss是谁. 2.初始化,开始boss都是自己,f[i]=i

并查集(基础)

并查集, 从这个名字上也可以知道是合并和查找集合的, 它也叫不相交的集的数据结构, 典型的例题有食物链, 来判断有多少个独立的树什么的, 下面一个例题,来简单的解释并查集:一个犯罪团伙一共有n个人, 现在只知道谁跟谁一伙, 来求出一共有多少个团伙, 代码如下: 1 #include <stdio.h> 2 //并查集 3 /*此案例是给定总个数, 从1到n, 然后给定谁和谁是一伙的, 4 输入一个m来确定一个有多少个一伙的, 求出最后一个有几伙*/ 5 int f[1000], n, m, k

poj1703(Find them, Catch them)并查集

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, the police first needs to identify which gang a criminal belongs to. The present