题目描述
现在有 个人,他们之间有两种关系:朋友和敌人。我们知道:
一个人的朋友的朋友是朋友
一个人的敌人的敌人是朋友
现在要对这些人进行组团。两个人在一个团体内当且仅当这两个人是朋友。请求出这些人中最多可能有的团体数。
输入格式
第一行输入一个整数 代表人数。
第二行输入一个整数 表示接下来要列出
个关系。
接下来 行,每行一个字符
和两个整数
,分别代表关系(朋友或敌人),有关系的两个人之中的第一个人和第二个人。其中
有两种可能:
如果 为 `
`,则表明
和
是朋友。
如果 为 `
`,则表明
和
是敌人。
输出格式
一行一个整数代表最多的团体数。
样例
样例输入
6
4
E 1 4
F 3 5
F 4 6
E 1 2
样例输出
3
提示
对于 的数据,
,
,
。
核心代码
1. 题目中“敌人的敌人就是朋友”可以理解成在遇到第二个或第二个以上个敌人时,需将这些敌人合并。
2. 在遇到朋友时直接合并。
void hb(int x,int y){ //合并的函数
int k=find(x),l=find(y);
if(k!=l) f[k]=l;
}
for(int i=1;i<=m;i++){
char ch;int a,b;
cin>>ch>>a>>b;
if(ch=='F') hb(a,b); //合并朋友
}else{ //合并敌人
if(!e[a]) e[a]=find(b);
else hb(e[a],b);
if(!e[b]) e[b]=find(a);
else hb(e[b],a);
}
}
统计部分
1. 前面的操作已经将所有敌人及朋友合并,所以用这里c数组记录所有合并后的点,即合并后每个人的祖先节点。
2. 用一个变量cnt统计被记录过的点。
int find(int x){ //查找祖先节点的函数
if(f[x]==x) return x;
else return f[x]=find(f[x]);
}
for(int i=1;i<=n;i++)
c[find(i)]++;
int cnt=0;
for(int i=1;i<=n;i++)
if(c[i]>0) cnt++;
完整代码
#include<bits/stdc++.h>
using namespace std;
int f[1005],e[1005],c[1005];
int find(int x){
if(f[x]==x) return x;
else return f[x]=find(f[x]);
}
void hb(int x,int y){
int k=find(x),l=find(y);
if(k!=l) f[k]=l;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=m;i++){
char ch;int a,b;
cin>>ch>>a>>b;
if(ch=='F') hb(a,b);
}else{
if(!e[a]) e[a]=find(b);
else hb(e[a],b);
if(!e[b]) e[b]=find(a);
else hb(e[b],a);
}
}
for(int i=1;i<=n;i++)
c[find(i)]++;
int cnt=0;
for(int i=1;i<=n;i++)
if(c[i]>0) cnt++;
cout<<cnt<<endl;
return 0;
}