Description
The “BerCorp” company has got n employees. These employees can use m approved official languages for the formal correspondence. The languages are numbered with integers from 1 to m. For each employee we have the list of languages, which he knows. This list could be empty, i. e. an employee may know no official languages. But the employees are willing to learn any number of official languages, as long as the company pays their lessons. A study course in one language for one employee costs 1 berdollar.
Find the minimum sum of money the company needs to spend so as any employee could correspond to any other one (their correspondence can be indirect, i. e. other employees can help out translating).
Input
The first line contains two integers n and m (2 ≤ n, m ≤ 100) — the number of employees and the number of languages.
Then n lines follow — each employee’s language list. At the beginning of the i-th line is integer ki (0 ≤ ki ≤ m) — the number of languages the i-th employee knows. Next, the i-th line contains ki integers — aij (1 ≤ aij ≤ m) — the identifiers of languages the i-th employee knows. It is guaranteed that all the identifiers in one list are distinct. Note that an employee may know zero languages.
The numbers in the lines are separated by single spaces.
Output
Print a single integer — the minimum amount of money to pay so that in the end every employee could write a letter to every other one (other employees can help out translating).
Sample Input
Input
5 5
1 2
2 2 3
2 3 4
2 4 5
1 5
Output
0
Input
8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1
Output
2
Input
2 2
1 2
0
Output
1
拿到这条题目,思路其实很简单,为了让员工可以相互沟通,即判断一个图有多少个连通子图。一般的,如果有n个连通子图,则需要学习的课程为n-1。
当然,这条题目有一种例外的情形,如果n个员工都不会说任意一种语言,则需要学习的课程就为n。
分析步骤如下:
1.如果n个员工均不会说任意一种语言,直接输出n;
2.否则,根据两两员工的状态,确定两点是否是连通的(有共同语言就连通,否则不连通)。
4.根据DFS,判断连通子图数目的大小,输出其减去1的值即可。
全局变量如下定义:
int graph[105][105];
int visited[105];
int language[105][105];
int n,m;
int piece;
分别是图、是否遍历的判断点、每个员工的语言学习情况表、图节点数目、语言数目、连通子图数目。
计算连通子图数目的DFS算法如下所示:
void traverse_r(int id)
{
int i;
visited[id]=1;
for(i=0;i<n;i++)
{
if(graph[id][i] && !visited[i])
traverse_r(i);
}
}
void traverse()
{
int i;
for(i=0;i<n;i++)
{
if(!visited[i])
{
traverse_r(i);
piece++;
}
}
}
图的构造算法如下所示:
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
for(k=0;k<105;k++)
if(language[i][k] && language[j][k])
{
graph[i][j]=graph[j][i]=1;
break;
}
}
最后统一一下所有代码:
#include<stdio.h>
#include<math.h>
#include<string.h>
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define ABS(x) (((x)>0)?(x):(-(x)))
#define bool int
#define true 1
#define false 0
#define TRUE 1
#define FALSE 0
#define int64 long long
#define MAXLEN 1000005
int graph[105][105];
int visited[105];
int language[105][105];
int n,m;
int piece;
void traverse_r(int id)
{
int i;
visited[id]=1;
for(i=0;i<n;i++)
{
if(graph[id][i] && !visited[i])
traverse_r(i);
}
}
void traverse()
{
int i;
for(i=0;i<n;i++)
{
if(!visited[i])
{
traverse_r(i);
piece++;
}
}
}
int main()
{
int i,j,k,x;
int allzero=1;
scanf("%d%d",&n,&m);
memset(graph,0,sizeof(graph));
memset(language,0,sizeof(language));
for(i=0;i<n;i++)
{
scanf("%d",&k);
if(k>0) allzero=0;
for(j=0;j<k;j++)
{
scanf("%d",&x);
language[i][x]=1;
}
}
if(allzero)
{
printf("%d\n",n);
return 0;
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
for(k=0;k<105;k++)
if(language[i][k] && language[j][k])
{
graph[i][j]=graph[j][i]=1;
break;
}
}
traverse();
printf("%d\n",piece-1);
return 0;
}
运行结果:Accept