洛谷1892 团伙

来源:互联网 发布:avdb新域名 编辑:程序博客网 时间:2024/05/16 10:45

题目描述

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

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

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

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

算法

第一眼看到这道题:诶?这不是并查集裸题吗?
事实也如此,对于朋友直接合并集合就行了,但是对于敌人应该怎么处理呢?
用数组f[i][j]来表示i和j是敌人,在每次输入敌人关系时循环合并即可。
这样这道题就变得十分简单了。

代码

#include <algorithm>#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;int root[1010]; //并查集 父节点 bool f[1010][1010]; //仇敌关系  int find(int x) //寻找根节点(有路径压缩) {    if (root[x]!=x) root[x]=find(root[x]);    return root[x];}void merge(int x,int y) //合并集合  {    int r1=find(x),r2=find(y);    if (r1!=r2) root[r2]=r1;}int main(){    ios::sync_with_stdio(false); //加速cin & cout     int n,m;    cin>>n>>m;    for (int i=1;i<=n;i++) root[i]=i; //初始化      while (m--)    {        char c; int a,b;        cin>>c>>a>>b;        if (c=='F') merge(a,b); //朋友就直接合并          else //仇敌关系          {            f[a][b]=f[b][a]=true; //先保存              for (int k=1;k<=n;k++) //再循环合并              {                if (f[a][k]) merge(b,k); //敌人的敌人是朋友                  if (f[b][k]) merge(a,k); //同上              }        }    }    int ans=0;    for (int i=1;i<=n;i++) //统计父节点数(也就是团伙数)         if (root[i]==i) ans++;    printf("%d\n",ans); //输出      return 0;}

后记

一开始作者这只蒟蒻看到仇敌关系也是很懵,但是这道题数据范围较小,所以我使用了这种暴力的方法。
不过这道题当作并查集练手题来做还是很好的!

原创粉丝点击