【并查集】BZOJ1370- [Baltic2003]Gang团伙

【题目大意】

在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

【思路】

水………NOIP的小孩都不屑于玩……

把i拆成i和i+n,其中i表示i的朋友,i+n表示i的敌人。对于(i,j):

(1)i,j是朋友,那么合并i和j。

(2)i,j不是朋友,那么合并i和j+n,j和i+n,代表敌人的敌人是我的朋友。

*注意,如果i和j是敌人,那么它们的敌人不一定是朋友。所有不要合并i+n和j+n。

好水啊……

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int MAXN=5000;
 7 int u[MAXN],h[MAXN],appear[MAXN];
 8 int n,m,gang;
 9
10 int find(int x)
11 {
12     int r=x,temp;
13     while (u[r]!=r) r=u[r];
14     while (x!=r)
15     {
16         temp=u[x];
17         u[x]=r;
18         x=temp;
19     }
20     return r;
21 }
22
23 void union_set(int fa,int fb)
24 {
25     if (h[fa]>=h[fb])
26     {
27         u[fb]=fa;
28         if (h[fa]==h[fb]) h[fa]++;
29     }
30     else u[fa]=fb;
31 }
32
33 void init()
34 {
35     for (int i=1;i<=2*n;i++)
36     {
37         u[i]=i;
38         h[i]=1;
39     }
40 }
41
42 void solve()
43 {
44     scanf("%d%d",&n,&m);
45     init();
46     for (int i=1;i<=m;i++)
47     {
48         char op[2];
49         int u,v;
50         scanf("%s%d%d",op,&u,&v);
51         if (op[0]==‘F‘)
52         {
53             int fa=find(u),fb=find(v);
54             if (fa!=fb) union_set(fa,fb);
55         }
56         else
57         {
58             int fa=find(u),fb=find(v+n);
59             if (fa!=fb) union_set(fa,fb);
60             fa=find(v),fb=find(u+n);
61             if (fa!=fb) union_set(fa,fb);
62         }
63     }
64 }
65
66 void getans()
67 {
68     for (int i=1;i<=n;i++) u[i]=find(i);
69     memset(appear,-1,sizeof(appear));
70     gang=0;
71     for (int i=1;i<=n;i++)
72     {
73         if (appear[u[i]]==-1)
74         {
75             gang++;
76             appear[u[i]]=1;
77         }
78     }
79     printf("%d",gang);
80 }
81
82 int main()
83 {
84     solve();
85     getans();
86     return 0;
87 }
时间: 2024-10-10 07:15:12

【并查集】BZOJ1370- [Baltic2003]Gang团伙的相关文章

bzoj1370 [Baltic2003]Gang团伙

题目链接 一道水题 把一个人分为两种人格:作为朋友时(i):作为敌人时(i+n) 拆点并查集维护关系 注意统计答案时要先find之后取个数而不是找fa[i]==i(1<=i<=n)的个数 因为一些人只作为敌人出现过所以find的结果可能是作为敌人的人格就统计不到,所以要先find 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5

续并查集学习笔记——Gang团伙题解

一言不合先贴题目 Description 在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1. 我朋友的朋友是我的朋友: 2. 我敌人的敌人是我的朋友: 所有是朋友的人组成一个团伙.告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙? Input 第1行为n和m,N小于1000,M小于5000: 以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人. Outpu

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

BZOJ 1370 Baltic2003 Gang团伙 并查集

题目大意:给定n个人,朋友的朋友是朋友,敌人的敌人是朋友,朋友之间组成一个团伙,求团伙数 将每个点x拆成两个:x和x+n 如果x和y是朋友,就将x和y合并 如果x和y是敌人,就将x和y+n合并,将y和x+n合并 注意敌人的朋友不一定是敌人,因此如果x和y是朋友,不能将x+n和y+n合并 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M

口袋的天空洛谷并查集

题目背景 小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空. 有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖. 题目描述 给你云朵的个数N,再给你M个关系,表示哪些云朵可以连在一起. 现在小杉要把所有云朵连成K个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小. 输入输出格式 输入格式: 每组测试数据的 第一行有三个数N,M,K(1<=N<=1000,1<=M<=10000,1<=K<=10) 接下来M个数每行三个数X,Y,

[qbzt寒假] 并查集

并查集: \(Kruscal\),\(Tarjan\)求\(LCA\) 分类并查集:食物链,团伙(敌人的敌人是我的朋友) 带权并查集:\(SDOI2016\)齿轮(可用 int father(int x) { return fa[x]==x?x:fa[x]=father(f[x]); } Luogu3101 滑雪等级[] 建边:任意相邻两格子之间建边,权值为海拔差 将边排序,从小往大一个一个往里加,当一个并查集内部有起点,并且大小(点数)>=T,这里面所有的起点的D=最后加入的边 #includ

【并查集】团伙

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

1034. Head of a Gang (30) -string离散化 -map应用 -并查集

题目例如以下: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone call

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

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