您的位置:首页 > 其它

【codevs2597/tyvj1602】团伙 解题报告

2015-09-19 19:37 323 查看
【codevs2597/tyvj1602】团伙  解题报告




描述

1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。 

而且有一点是肯定的,就是A的朋友的朋友是A的朋友;A的敌人的敌人也是A的朋友。 

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


输入格式

输入的第一行为N(2<=N<=1000),表示强盗的个数(从1编号到N)。 

第二行M(1<=M<=5000),表示信息条数。 

以下M行,每行可能是F p q或是E p q,分别表示p和q是朋友,或是敌人。 

假设输入不会产生矛盾


输出格式

输出只有一行,表示最大可能的团伙数。


测试样例1


输入





E 1 4 

F 3 5 

F 4 6 

E 1 2


输出

3

【解题思路】

经典的并查集题目,但是需要一点小小的技巧;

如果是朋友的话,直接把两个合并起来就行了;如果是敌人,那么就不合并;但是如果是敌人的敌人,就是朋友了,所以这种情况也要合并起来;

设一个数组,存下每一个点的所有的敌人,因为敌人的敌人是朋友,两个敌人的敌人都是这个点,所以他们俩一定是朋友,,所以我们要把这个点所有的敌人两两合并起来;

最后查找一下一共有几个集合,也就是有几个代表元素,就是最大的团伙的数目;

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,i,j,k,x,y,ans;
int a[1005][1005],f[1005],num[10005];
bool b[1005];
char p;

int find(int x)
{
if (f[x]==x) return f[x];
f[x]=find(f[x]);
return f[x];
}

void merge(int x,int y)
{
int n1=find(x);
int n2=find(y);
f[n2]=n1;
return;
}

int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
f[i]=i;
for (i=1;i<=m;++i)
{
cin>>p;
scanf("%d%d",&x,&y);
if (p=='F')
merge(x,y);
if (p=='E')
{
a[x][++num[x]]=y;
a[y][++num[y]]=x;
}
}
for (k=1;k<=n;++k)
{
for (i=1;i<=num[k];++i)
for (j=i;j<=num[k];++j)
merge(a[k][i],a[k][j]);
}
for (i=1;i<=n;++i)
k=find(i);
for (i=1;i<=n;++i)
b[f[i]]=true;
for (i=1;i<=n;++i)
if (b[i])
ans++;
printf("%d",ans);
return 0;
}
【犯的错误】

在最后的时候,要注意再进行一次路径压缩,使所有集合里的点都指向一个代表元素。在合并的过程中路径压缩会有遗漏,会出现虽然在一个集合里,但指向不同的代表元素的情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: