F - 娜娜夢游仙境系列——多民族王國


F - 娜娜夢游仙境系列——多民族王國

Time Limit:  2000/1000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others)

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個人,有相同語言的人連一條邊,問還需要添加多少條邊才能使圖完全連通。

解法:可以用並查集來維護圖的連通性,或者直接dfs或bfs來計算連通塊數。若只有一個連通塊答案為0(因為所有人都能無障礙間接或直接交流),每多一個連通塊就要增加一條邊,所以答案是連通塊數-1,但是有一種特殊的情況就是所有人都不會語言,那么這種情況需要特判,答案為人數(即每個人都學同一種語言)。

note:秩其實還沒搞懂具體怎么用的。。。

 1 #include <stdio.h>
2 #include <string.h>
3 #define MAXSIZE 205
4
5 int uset[MAXSIZE],rank[MAXSIZE];
6
7 void makeSet(int size) //為每個數創建集合,指向自己,rank保存秩
8 {
9 int i;
10 for(i = 0;i < size;i++)
11 {
12 uset[i] = i;
13 rank[i] = 0;
14 }
15 }
16
17 int find(int x) { //路徑壓縮,把所有元素指向根
18
19 if (x != uset[x])
20 uset[x] = find(uset[x]);
21 return uset[x];
22
23 }
24
25 int unionSet(int x, int y) { //聯合兩個集合,返回是否兩個不同集合
26
27 if ((x = find(x)) == (y = find(y)))
28 return 0;
29 if (rank[x] > rank[y])
30 uset[y] = x;
31 else
32 {
33 uset[x] = y;
34 if (rank[x] == rank[y])
35 rank[y]++;
36 }
37 return 1;
38 }
39
40 int main()
41 {
42 int t,i,j,s,k,mark,ski,n,m,p,q,l,sum;
43 while(scanf("%d",&t)==1)
44 {
45 while(t--)
46 {
47 scanf("%d %d",&n,&m);
48 s=sum=0;
49 makeSet(MAXSIZE);
50 for(i=1;i<=n;i++)
51 {
52 scanf("%d",&ski);
53 if(ski==0)
54 sum++;
55 for(j=0;j<ski;j++)
56 {
57 scanf("%d",&k);
58 p=unionSet(k+100,i); //把語言種類+100放到人物i中
59 if(p==0) //說明該語言別的人會
60 {
61 q=find(k+100);
62 unionSet(i,q); //把該人物和能交流的另一個人放入一個集合
63 //q=q<i?q:i;
64 //mark=1;
65 }
66 }
67 }
68 if(sum==n) //所有人會的語言為0
69 printf("%d\n",n);
70 else
71 {
72 for(i=1;i<=n;i++)
73 {
74 if(uset[i]==i) //根指向自身,所以滿足的話就是一個集合,否則是屬於別的集合的,即是相關的。
75 s++;
76 }
77 printf("%d\n",s-1); //n個集合,只要n-1個邊就可以了
78 }
79 }
80 }
81 return 0;
82 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com