并查集之团伙(codevs)

2597 团伙

时间限制: 1 s

空间限制: 128000 KB

题目描述

1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是:

我朋友的朋友是我的朋友;

我敌人的敌人也是我的朋友。

两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。

输入描述

输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。 第二行M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。输入数据保证不会产生信息的矛盾。

输出描述

输出文件gangs.out只有一行,表示最大可能的团伙数。

样例输入

6
4
E 1 4
F 3 5
F 4 6
E 1 2

样例输出

3

数据范围及提示

2<=N<=1000

1<=M<=5000

1<=p q<=N

#include<cstdio>
int n,m,f[1005],x,y,x1,y1,ans=0,g[1002][1002];
bool z[1005];
char q,p;
int find(int x)
{
    if(x==f[x]) return f[x];//找到的是根,返回;
    else {f[x]=find(f[x]);return f[x];}//如果不是根,将x的祖先赋值为根(缩短下一次找的路径);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%s%d%d",&q,&x,&y);//读入用%s,不能用%c(在这错了好长时间,可能是我水平低) ;
        x1=find(x);
        y1=find(y);
        if(q==‘F‘) f[x1]=y1;
        else{
            g[x][0]++;g[x][g[x][0]]=y;
            g[y][0]++;g[y][g[y][0]]=x;//用二维数组存敌人关系 ;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=g[i][0];j++)
        {
            x=g[i][j];
            if(j>1) {            //将i的敌人合并;
                x1=find(g[i][j-1]);
                y1=find(f[x]);
                f[x1]=y1;
            }
            for(int k=1;k<=g[x][0];k++){//将i与j的敌人合并;
                x1=find(i);
                y1=find(g[x][k]);
                f[x1]=y1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        x=find(f[i]);
        if(!z[x]) {ans++;z[x]=1;} //每个根只加一次;
    }
    printf("%d",ans);
    return 0;
}

时间: 2024-08-10 11:52:24

并查集之团伙(codevs)的相关文章

【并查集】团伙

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

[codevs 1995]黑魔法师之门(并查集)

题目:http://codevs.cn/problem/1995/ 分析:脑补一下满足题目要求的子图肯定就是环……于是题目就变成了不断加边求环的个数.看起来有点麻烦……但是环的实质是几个小环组合起来的……所以我们只需要知道最基础的环的个数就行了,根据二项式定理那么就是2^(最基础的环的个数)-1.还是不好做啊!!!!!! 没关系……并查集来了…… 假设对于第i-1操作后,最终答案为ans,那么对于第i次操作,分为两种情况 ①加入这条边后,没有出现新环,那么说明对结果无影响,结果还是ans ②加入

codevs 3372 选学霸(hash+并查集+多重背包)

先通过并查集处理出来有多少种不同的集合,每个集合有多少人.一定要不要忘记了与别的没有联系的独立点. 并查集的时候可以通过hash处理出来每个数目相同的集合的个数. 这样以人数为权值,个数为限制进行多重背包,结果就是答案. 题目链接:http://codevs.cn/problem/3372/ #include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #in

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

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

codevs 1078最小生成树 Kruskal+并查集

题目描述 Description 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助. 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场.为了使花费最少,他想铺设最短的光纤去连接所有的农场. 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案. 每两个农场间的距离不会超过100000 输入描述 Input Description 第一行: 农场的个数,N(3<=N<=100).

codevs 1073 家族 并查集

没什么可以说的,并查集裸题,标签难度和实际不成正比啊,存个板子: 1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 23333 4 int n,m,p,fa[maxn]; 5 int getf(int); 6 int find(int,int); 7 int main() 8 { 9 scanf("%d %d %d",&n,&m,&p); 10 for(int i=1;i<

codevs 1001 舒适的路线 (并查集)

题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光. Z小镇附近共有 N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤5000)条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路.也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi.频繁的改变速度使得游客们很不舒服,因此大家从一个景点前往另一个景点的时候,都希望选择行使过程中最大速度和最小速度的

codevs 1069 关押罪犯 并查集

很有意思的一道题.刚开始看不出这是道并查集,后来看了题解才会做,就是把要分开的囚犯放在同个集合里,表示这两个囚犯不在同一间监狱,但不是直接合并,例如1和2要分开,则1和2’.1’和2合并(x’为x的虚点),同个集合中实点和虚点分属于两间监狱(即x’与y在不同监狱):再例如,1和2,2和3要分开,则1和2’合并,2’和3合并,那么1和3会在同一间监狱,1’和2合并,2和3’合并,那么2就在另一间监狱.这样一来整道题的思路就呼之欲出了:按仇恨值从大到小分开每对囚犯,若出现无法分开的情况(即已在同一个

[并查集]团伙

题号: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)