团伙
作者:互联网
题目:
团伙
题目链接:https://www.luogu.com.cn/problem/T241093?contestId=69902
题目描述
现在有 nn 个人,他们之间有两种关系:朋友和敌人。我们知道:
- 一个人的朋友的朋友是朋友
- 一个人的敌人的敌人是朋友
现在要对这些人进行组团。两个人在一个团体内当且仅当这两个人是朋友。请求出这些人中最多可能有的团体数。
输入格式
第一行输入一个整数 nn 代表人数。
第二行输入一个整数 mm 表示接下来要列出 mm 个关系。
接下来 mm 行,每行一个字符 optopt 和两个整数 p,qp,q,分别代表关系(朋友或敌人),有关系的两个人之中的第一个人和第二个人。其中 optopt 有两种可能:
- 如果 optopt 为
F
,则表明 pp 和 qq 是朋友。 - 如果 optopt 为
E
,则表明 pp 和 qq 是敌人。
输出格式
一行一个整数代表最多的团体数。
输入输出样例
输入 #16 4 E 1 4 F 3 5 F 4 6 E 1 2输出 #1
3
说明/提示
对于 100\%100% 的数据,2 \le n \le 10002≤n≤1000,1 \le m \le 50001≤m≤5000,1 \le p,q \le n1≤p,q≤n。
解题思路:
这道题是一个并查集,用father函数来进行合并父亲结点。
首先,如果两人是朋友,那么就把两人合并。
除此之外,我们再维护一个e[i],表示i的一个敌人。如果两人是敌人,那么如果e[i]为空,就更新e[i],否则,就把e[i]和j合并。根据敌人的敌人是朋友的原则,如果j和i是敌人,那么j同e[i]则是朋友,所以合并。同样的,对于i和e[j],也是如此。最后统计一下根结点就行了。
参考代码:
#include<iostream>
using namespace std;
int root[1001]={0};
int relate[1001][1001]={0};
int father(int n){
if (root[n]==-1)
{
return n;
}
else return father(root[n]);
}
int hb(int x,int y){
int n,m;
n=father(x);
m=father(y);
if (n<m){
root[m]=n;
}
else {
root[n]=m;
}
return 0;
}
int mains(){
int n,m;
int i,j,k;
char c;
int x,y;
cin>>n>>m;
for (i=1;i<=1001;i++)
{
root[i]=-1;
}
for (i=1;i<=m;i++)
{
cin>>c>>x>>y;
if (c=='E')
{
relate[y][x]=1;//记录相互的关系
relate[x][y]=1;
}
if (c=='F')
{
hb(x,y);
}
}
for (i=1;i<=n;i++){//遍历关系,合并我的敌人的敌人即朋友
for (j=1;j<i;j++)//通过以当前位置的前一位置向下辐射,即每次查找一个方阵
{
if(relate[i][j]){
for (k=1;k<i;k++)//小于i是为了防止二次合并,即构成方阵
{
if (relate[j][k])
{
hb(k,i);
}
}
}
}
cout<<endl;
}
int s=0;
for (i=1;i<=n;i++)
{
if (root[i]==-1)s++;
}
cout<<s;
return 0;
}
标签:le,int,relate,father,朋友,root,团伙 来源: https://www.cnblogs.com/kenty/p/16412618.html