原题:团伙
由题可知,两个人之间的关系只有 敌人 或 朋友 两种情况
再根据题目,还有两种特殊情况需要判断:
1.我朋友的朋友是我的朋友;
2.我敌人的敌人也是我的朋友。
先解决情况1:
根据题意,要处理这种关系,很明显要运用并查集,如果两人之间是朋友,将两人所在的集合合并,否则不合并,将所有朋友团伙联合在一起,情况1就解决了。
接下来看情况2:
仔细分析,发现合并之前要先知道敌人的敌人是谁。为此,我们设enermy[x]表示第x个人的敌人,当第i个人与第x个人为敌时,i就与enermy[x]合并,成为朋友,这样情况2就迎刃而解了。
#include<iostream>
using namespace std;
//Problem need(题目所需):
int n,m,x,y;
char z;
//Union-find set need(并查集所需):
int father[1005],en[1005]/*enermy数组*/,ans;
bool b[1005];//记录团伙是否被寻找过
int myfind(int x)//递归方式寻找根
{
if(father[x]!=x) father[x]=myfind(father[x]);
return father[x];
}
void unionn(int x,int y)//合并两人的团伙
{
x=myfind(x);
y=myfind(y);
father[y]=x;
}
int main()
{
cin>>n>>m;
/*-------初始化-------*/
for(int i=1;i<=n;i++)
father[i]=i;//最开始所有人以自己为一个团伙
/*-------------------*/
for(int i=1;i<=m;i++)
{
cin>>z>>x>>y;
if(z=='F')
{
unionn(x,y);//当x与y为朋友时,直接联合
}
else//否则就为敌人
{
if(en[x])//如果x有敌人,那么x的敌人与y联合
unionn(en[x],y);
else
if(en[y])//如果y有敌人,那么y的敌人与x联合
unionn(en[y],x);
en[x]=y;//互相标记为敌人
en[y]=x;//不用担心覆盖,因为x和y已经连上自己的团伙
}
}
for(int i=1;i<=n;i++)
if(!b[myfind(i)])//寻找团伙数量
{
ans++;
b[myfind(i)]=1;
}
cout<<ans;
return 0;
}