简述题意:
农夫约翰的N(2<=N<=10,000)只奶牛标号为1..N,同样的有M(1<=M<=30,000)种牛语标号为1..M,第i只奶牛会说K_i(1<=K_i<=M)种牛语,分别为L_i1,L_i2,…,L_{iK_i}(1<=L_ij<=M),农夫的奶牛不是特别聪明,所以K_i的累加和不大于100,000。
两只奶牛只有当他们至少有一门语言一样的时候才可以沟通。否则这两只奶牛就需要别人来帮他们翻译才能交流。换句话说,A和B要进行沟通,他们可以通过T_1,T_2,…,T_k来传递,比如A和T_1,T_1和T_2,…,T_k和B进行交流。
农夫希望他的奶牛可以多多沟通,所以他买了很多课本去教她的奶牛语言。当然农夫非常的吝啬,他希望买最少的书就可以让所有的奶牛可以交流。你的任务就是帮他算出最少需要买几本书。
难度:NOIP-
算法:并查集
题解:
对于每头牛,把他自己与他会的语言连边即可。
利用并查集,进行查找。
但是,luogu #1数据有问题,#1是样例,后面的测试数据output只有 “最少需要买几本书”
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define N 10005
#define M 30005
using namespace std;
int fa[N+M];
int vis[N];
int findf(int x)
{
if(x==fa[x]) return x;
return fa[x]=findf(fa[x]);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n+m;i++)
{
fa[i]=i;
}
for(int i = 1;i <= n;i++)
{
int c;
scanf("%d",&c);
for(int j = 1;j <= c;j++)
{
int x;
scanf("%d",&x);
int t1=findf(x+n);
int t2=findf(i);
if(t1!=t2) fa[t1]=t2;
}
}
for(int i = 1;i <= n;i++) vis[findf(i)]=1;
int ans=0;
int a,b;
for(int i = 1;i <= n;i++)
{
if(vis[i]) ans++;
}
printf("%d\n",ans-1);
return 0 ;
}