F - 娜娜梦游仙境系列——多民族王国
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
娜娜好不容易才回忆起自己是娜娜而不是什么Alice,也回忆起了自己要继续探索这个世界的目标,便偷偷溜出皇宫。娜娜发现这个王国有很多个民族组成,每个民族都有自己的方言,更要命的是这些方面差别还很远,这就导致这个王国的人民交流十分困难。娜娜仔细观察并记录了好久,发现总共有m种不同的语言。
突然娜娜发现前面有一群天才在讨论问题,但是奈何语言问题,导致这群人交流非常吃力。不过幸亏的是,这群天才都有一个特殊的能力,只要消耗一个单位的能量即可完全领悟一门新的语言(妈妈再也不用担心我的四六级托福雅思GRE!)。于是娜娜久违的的好奇心又开始冒泡了,娜娜希望你告诉她,如果知道了每个人会的语言,是否能让这群天才两两直接或者间接的交流呢?所谓间接得交流是指经过若干个人的翻译使两个人得到相互表达的信息。如果不能,至少需要多少能量才能实现呢?
Input
多组数据,首先是一个正整数t(t<=20)
对于每组数据,首先是两个整数n,m(2<=n<=100,1<=m<=100),分别代表人数以及语言的种类数,语言的编号从1~m。
接下来是n行,每行对这个人进行描述
首先是一个整数k,表示这个人已经会k门语言,接下来是k个整数,分别是这个人掌握的语言编号。(0<=k<=m)
Output
对于每组数据,输出一个整数,表示使得这群人能够互相直接或者间接交流所需要的最少能量。
Sample Input
2 2 2 1 2 0 5 5 1 2 2 2 3 2 3 4 2 4 5 1 5
Sample Output
1 0
Hint
样例1中其中第一个人会第二种语言,而第二个人不会任何语言,所以只需要第二个人也学会第二种语言即可交流,所以能量数为1
样例2中有5个人,而且这5个人已经可以相互直接或间接进行交流: 1-2-3-4-5,正好构成一条链。因此不需要继续学习新的语言,能量数为0。
题意:
输入N和M表示有多少个人和语言的种类,然后再输入每一个人所掌握的语言,并查集的题目,由于数据量比较小,所有采用了用二维数组来保持关系,
A_B[i][j]表示编号i的人对于语言j是否掌握,1表示掌握,2表示不掌握。通过关系,构建并查集来连接判断能够构成多少条边,判断边数来判断答案、
1 #include <iostream> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 using namespace std; 6 int uset[3333],num[3333],parper[3333]; 7 int A_B[110][110]; 8 int Find(int x) 9 { 10 int p=x,t; 11 while(uset[p]!= p) 12 p=uset[p]; 13 while(x!=p) 14 {t=uset[x];uset[x]=p;x=t;} 15 return x; 16 } 17 int main() 18 { 19 int T,n,m,k,i,j,l,get,A,B,Begin; 20 int Num[110],Max; 21 scanf("%d",&T); 22 while(T--) 23 { 24 memset(A_B,0,sizeof(A_B)); 25 scanf("%d %d",&n,&m); 26 { 27 for(i=0;i<n;i++)uset[i]=i; 28 for(i=0;i<m;i++)Num[i]=0; 29 for(i=0;i<n;i++) 30 { 31 scanf("%d",&k); 32 parper[i]=i;uset[i]=i;num[i]=1; 33 for(j=0;j<k;j++) 34 { 35 scanf("%d",&get); 36 A_B[i][get-1]=1; /*记录关系*/ 37 } 38 } 39 for(j=0,Max=0,Begin=0;j<m;j++) 40 { 41 for(i=0;i<n;i++) 42 { 43 if(A_B[i][j]==1) /*查找第一个人所掌握的语言*/ 44 { 45 Num[j]++; 46 if(Max<Num[j])Max=Num[j]; 47 for(l=i+1;l<n;l++) 48 { 49 if(A_B[l][j]==1) /*查找第其他人所掌握同样的语言*/ 50 { 51 A=Find(i); 52 B=Find(l); 53 if(A!=B) /*判断是否产生新的边*/ 54 { 55 Begin++; /*新的边,则边数加1*/ 56 uset[A]=B; /*判断是否产生新的边*/ 57 } 58 } 59 } 60 break; 61 } 62 } 63 } 64 if(Begin==0)printf("%d\n",n-Max); 65 else if(Begin>=n-1)printf("0\n"); 66 else printf("%d\n",n-1-Begin); 67 } 68 } 69 return 0; 70 }