一,需要开o2才能AC的代码

用emys[i]存储第i个人的敌人数,vector<long long>emyr[i]存储i个人的所以敌人,fa[i]存储第i个人的大boss。

1.初始化   把fa[i]全部设为i

2.在输入时如果u跟v是朋友,则join(u,v);否则说明是敌人,那么u,v的敌人数++,再各自把对方加入自己的敌人中

3.遍历所有人,如果某一人的敌人数>1,则让他的所有敌人两两组队

4.最后数一下有多少个大boss就能知道有多少个团体了。

代码:


#include <bits/stdc++.h>
using namespace std;
long long n,m,fa[1000001],emys[1000001],ans,u,v,a,b;
vector<long long>emyr[10001];
char t;
long long find(int x)
{if(fa[x] == x) return x;else return find(fa[x]);
}
void join(int a,int b)
{int x = find(a),y = find(b);if(x != y) fa[x] = y;
}
int main()
{scanf("%lld%lld",&n,&m);for(int i = 1; i <= n; i++) fa[i] = i;for(int i = 1; i <= m; i++){scanf("%s%lld%lld",&t,&u,&v);if(t == 'F') join(u,v);else{emys[u]++;emys[v]++;emyr[u].push_back(v);emyr[v].push_back(u);}}
//  for(int i = 1; i <= n; i++) cout<<emys[i]<<" ";
//  cout<<endl;
//  for(int i = 1; i <= n; i++)
//  {
//    for(int j = 0; j < emyr[i].size(); j++)
//      cout<<emyr[i][j]<<" ";
//    cout<<endl;
//  }for(int i = 1; i <= n; i++){if(emys[i] > 1){for(int j = 0; j < emys[i]; j++)for(int k = j + 1; k < emys[i]; k++)join(emyr[i][j],emyr[i][k]);}}for(int i = 1; i <= n; i++)if(fa[i] == i)ans++;printf("%lld",ans);return 0;
}

没开o2优化:

开了o2优化:


二,不用开o2优化也能AC的代码(1)

首先,要充分理解题目。 “敌人的敌人就是朋友”可以这么理解:如果一个人有两个或更多敌人,这些敌人就应该被合并。

代码中的emy数组就是记录了每个人的第一个敌人,再遇到敌人时就把这两个敌人合并。

其他的跟前面一样。

没想出这点的话还是蛮难做的。


#include <bits/stdc++.h>
using namespace std;
long long n,m,fa[1000001],emys[1000001],ans,u,v,a,b;
vector<long long>emyr[10001];
char t;
long long find(int x) //寻找x的大boss
{if(fa[x] == x) return x;else return find(fa[x]);
}
void join(int a,int b)//合并
{int x = find(a),y = find(b);if(x != y) fa[x] = y;
}
int main()
{scanf("%lld%lld",&n,&m);for(int i = 1; i <= n; i++) fa[i] = i;for(int i = 1; i <= m; i++){scanf("%s%lld%lld",&t,&u,&v);if(t == 'F') join(u,v);//是朋友就合并 else{if(emys[u] == 0) emys[u] = find(v);//一个人有两个或更多敌人,合并他们 else join(v,emys[u]);if(emys[v] == 0) emys[v] = find(u);else join(u,emys[v]);}}
//  for(int i = 1; i <= n; i++) cout<<emys[i]<<" ";
//  cout<<endl;
//  for(int i = 1; i <= n; i++)
//  {
//    for(int j = 0; j < emyr[i].size(); j++)
//      cout<<emyr[i][j]<<" ";
//    cout<<endl;
//  }
//  for(int i = 1; i <= n; i++)
//  {
//    if(emys[i] > 1)
//    {
//      for(int j = 0; j < emys[i]; j++)
//        for(int k = j + 1; k < emys[i]; k++)
//          join(emyr[i][j],emyr[i][k]);
//    }
//  }for(int i = 1; i <= n; i++)if(fa[i] == i)ans++;printf("%lld",ans);return 0;
}

三,引入反集

a 表示 a 的朋友集,a + n 表示 a 的敌人集

1.如果 a 和 b 是朋友,那么 将 a 和 b 的朋友集 相连即可: p[find(a)] = find(b);
2/如果 a 和 b 是敌人,则 将 a 的敌人集与 b 的朋友集 相连,将 b 的敌人集与 a 的朋友集 相连,即: p[find(a + n)] = Find(b),p[find(b + n)]  =  find(a)
最后统计有多少团伙时,1 ~ n 中(朋友集)所有 p[i] == i 的人数就是答案。因为根据题意,所有团伙一定会分布在朋友集中,因此 只要在朋友集中统计没有祖先的节点个数即可。

代码(以下代码转载自洛谷 P1892 [BOI2003]团伙(并查集变种 反集)_Brightess的博客-CSDN博客):

#define _CRT_SECURE_NO_WARNINGS 1
#include <bits/stdc++.h>using namespace std;
//#define int long long
int n, m;
const int N = 1010;
int p[N << 1];int Find(int x)
{if (p[x] != x) p[x] = Find(p[x]);return p[x];
}signed main()
{int T = 1; //cin >> T;while (T--){cin >> n >> m;int res = 0;for (int i = 1; i < N<<1; ++i) p[i] = i;for (int i = 1; i <= m; ++i){char op[2]; int a, b;cin >> op >> a >> b;int pa = Find(a), pb = Find(b);int pan = Find(a + n), pbn = Find(b + n);if (*op == 'F'){p[pb] = pa;}else{p[pbn] = pa;p[pan] = pb;}}for (int i = 1; i <= n; ++i) if (p[i] == i) ++res;cout << res << '\n';}return 0;
}

精讲并查集经典习题:P1892 [BOI2003]团伙(超详细)相关推荐

  1. P1892 [BOI2003]团伙(反集)

    P1892 [BOI2003]团伙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 现在有 nn 个人,他们之间有两种关系:朋友和敌人.我们知道: 一个人的朋友的朋友是朋友 ...

  2. P1892 [BOI2003]团伙(并查集,反集)难度⭐⭐★

    题目链接 反集 如果a和b是敌人,合并n+b和a,n+a和b 如果c和a是敌人,合并n+c和a,n+a和c 那么b和c自然就合并在一起了 这样就符合了题目敌人的敌人是朋友的规则 注意 并查集不要忘了初 ...

  3. How Many Answers Are Wrong HDU - 3038(带权并查集经典题,满满的都是注释)

    How Many Answers Are Wrong HDU - 3038  点击打开链接 题意:现在有n个数(你并不知道这n个数是什么),m次查询,每次查询给出u,v,w.表示从第u个数到第v个数的 ...

  4. 【POJ - 1182】 食物链(附超详细讲解)(并查集--种类并查集经典题)

    题干: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.  现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.  ...

  5. 洛谷 P1892 [BOI2003]团伙(并查集变种 反集)

    [BOI2003]团伙 题目描述 现在有 n n n 个人,他们之间有两种关系:朋友和敌人.我们知道: 一个人的朋友的朋友是朋友 一个人的敌人的敌人是朋友 现在要对这些人进行组团.两个人在一个团体内当 ...

  6. 并查集经典应用之染色模型

    3115. 疯狂的馒头 - AcWing题库 思路: 由于一个点最后的颜色取决于最后一次染色,那么我们可以倒着染色, 每染色一个点就将这个点删掉并记录颜色. 用ptr[i] 表示第i 个元素后面第一个 ...

  7. P1892 [BOI2003]团伙 +食物链 POJ - 1182 (并查集+思维)

    思路①: 开数组enem[i]记录节点i的敌对节点,当再次输入i的敌对节点时就把他所在并查集的根节点和enem[i]并起来. #include<bits/stdc++.h> using n ...

  8. 洛谷P1892 [BOI2003]团伙

    链接:P1892 题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两 ...

  9. BZOJ1370洛谷P1892 [BOI2003]团伙

    并查集 我们将a的敌人定义为a+n,b的敌人的定义为b+n,所以a与b+n是一类人,b与a+n是一类人,然后就这么合并就好了 代码 //By AcerMo #include<cmath> ...

最新文章

  1. 802.11 MESH WLANs
  2. torch模拟sigmoid
  3. 2022 年营销自动化七大趋势前瞻
  4. u盘linux软件下载,u盘linux制作工具(Universal USB Installer)
  5. 工具_HBuilder使用快捷方式
  6. Android之使用AlertDialog.Builder类创建带列表的对话框和带自己所布局视图的对话框
  7. Swift仿写喜马拉雅FM
  8. python题目训练(随时更新)
  9. JAVAWeb使用POI做导出Excel
  10. 进度计划中的时间相关术语
  11. matlab运行出现:Optimization terminated.
  12. Python自动生成新闻报告
  13. 计算机与电气工程sci期刊,电气工程专业什么SCI期刊比较好
  14. jpg图片太大怎么压缩变小
  15. 福建中医药大学数字化校园应用及数据容灾系统181万
  16. windows杀死进程
  17. 堆垛实训报告总结_叉车实训总结
  18. post请求302以及post请求变更为get请求的问题排查小记
  19. 如何将C 项目部署到云服务器上,如何将C 应用程序放在云服务器上
  20. python:print函数打印空行

热门文章

  1. 阿里官方Redis开发规范
  2. 51单片机定时器及其应用(2)(测量脉冲宽度)
  3. MetaWork:拜托,这样远程结对编程超酷的
  4. JCJC错别字检测新功能:检测日期格式
  5. 2030,保时捷全面抛弃燃油车
  6. Spring Cloud Alibaba 服务消费者调用 nacos 服务报错:java.net.UnknownHostException: xxx
  7. Unity AVPro视频播放路径问题(andriod和pc)
  8. 零一块学计算机二级题库,计算机二级office
  9. 推荐一个ps3的六轴手柄在windows下的驱动
  10. 使用 Antlr 开发领域语言