2597 团伙 并查集

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 黄金 Gold

题目描述 Description

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

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

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

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

输入描述 Input Description

输入文件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是敌人。输入数据保证不会产生信息的矛盾。

输出描述 Output Description

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

样例输入 Sample Input

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

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

2<=N<=1000

1<=M<=5000

1<=p q<=N

一看到题目就想到拓展域的并查集,有两个域一个是朋友域,一个是敌人域。但是写了发现不对,以后再想想。

后来看了题解想到了就再开一个数组存一下敌人。然后就是敌人的敌人就是朋友。我会对代码加入自己的理解。。。

下面是代码:

#include<bits/stdc++.h>
using namespace std;
int fa[5005],c[5005];//c就是存储敌人的数组
int find(int x)
{
  if(x == fa[x]) return x;
  return fa[x] = find(fa[x]);
}
void merge(int x,int y)
{
  fa[find(x)] = find(y);
}
int main ()
{
  int n,m;
  cin>>n>>m;
  for(int i = 1;i<=n;i++)
   fa[i] = i;
  char str;
  for(int i =  1;i<=m;i++)
   {
     int a,b;
     cin>>str>>a>>b;
     if(str == 'F')
      merge(a,b);//直接合并
     else {
       if(c[a] == 0)//当敌人数组c[a]为0时
       c[a] = find(b);//把此时的输入进去的b存入数组中去
       else fa[find(c[a])] = find(b);//当再次遇到c[a]是此时不为0,那么c[a]中的存储即为当时a的敌人,fa[find(c[a])] = find(b),把它拆开来看,就是将c[a] 连接到现在的y上,那么此时的c[a]是那时的敌人即为:样例的find(4) 连接到5上,两者都是敌人,即为敌人的敌人是朋友。
       if(c[b] == 0)//同理,不能忘记还有相反的情况
       c[b] = find(a);
       else fa[find(c[b])] = find(a);
     }
   }
   int ans = 0;
   for(int i =1;i<=n;i++)
   {
     if(fa[i] == i) ans++;//最后扫一遍各个点,存在多少个根节点,即为有多少个答案。
   }
   cout<<ans<<endl;
  return 0 ;
}

最后我发现了拓展域的写法:(不是自己写的)就不加上去了。。。有时间看懂了写一下。%%%

猜你喜欢

转载自blog.csdn.net/strategist_614/article/details/81089894