题目:有P个人和T棵树。现在给你某个人听到某棵树倒下声音的一些二元组,如果两个人听到的树的集合相同他们就是同一集合,问人分成几个集合。
分析:并查集。因为数据量很小(100)所以直接暴力判断是否相同即可,然后利用并查集处理合并,最后查询并查集中根(sets(i) = i)的个数即是结果。
注意:memset在<string>中;恶心的输入格式。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
//union_set
int sets[205];
int sums[205];
int rank[205];
//初始化
void Union_set( int a, int b )
{
for ( int i = a ; i <= b ; ++ i ) {
sets[i] = i;
sums[i] = 1;
rank[i] = 0;
}
}
//返回根节点
int Find( int a )
{
if ( a != sets[a] )
sets[a] = Find( sets[a] );
return sets[a];
}
//合并集合
void Union( int a, int b )
{
if ( rank[a] < rank[b] ) {
sets[a] = b;
sums[b] += sums[a];
}else {
if ( rank[a] == rank[b] )
rank[a] ++;
sets[b] = a;
sums[a] += sums[b];
}
}
//union_set end
int P_T[101][101];
//判断相统集合
int same( int p1, int p2, int t )
{
for ( int i = 1 ; i <= t ; ++ i )
if ( P_T[p1][i] != P_T[p2][i] )
return 0;
return 1;
}
int main()
{
int n,t,p,T,P,a,b;
while ( ~scanf("%d",&n) ) {
getchar();getchar();
for ( int k = 0 ; k < n ; ++ k ) {
if ( k > 0 ) printf("\n");
scanf("%d%d",&P,&T);
getchar();
Union_set( 1, P+T );
memset( P_T, 0, sizeof(P_T) );
while ( 1 ) {
char c = getchar();
ungetc(c,stdin);
if ( c == '\n' || c == EOF ) break;
scanf("%d%d",&p,&t);
getchar();
P_T[p][t] = 1;
}
//合并集合
for ( int i = 1 ; i <= P ; ++ i )
for ( int j = i+1 ; j <= P ; ++ j ) {
a = Find( i );
b = Find( j );
if ( a != b && same( a, b, T ) )
Union( a, b );
}
//查询集合的个数
int sum = 0;
for ( int i = 1 ; i <= P ; ++ i )
sum += (i == Find(i));
printf("%d\n",sum);
}
}
return 0;
}