BZOJ 3296 [USACO2011 Open] Learning Languages:並查集

Leohh發表於2017-10-20

題目連結:http://www.lydsy.com/JudgeOnline/problem.php?id=3296

題意:

  農夫約翰的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)。

  FJ的奶牛不太聰明,所以K_i的總和至多為100,000。

  兩頭牛,不能直接交流,除非它們都會講某一門語言。然而,沒有共同語言的奶牛們,可以讓其它的牛給他們當翻譯。換言之,牛A和B可以談話,當且僅當存在一個序列奶牛T_1,T_2,...,T_k,A和T_1都會說某一種語言,T_1和T_2也都會說某一種語言...並且T_k和B會說某一種語言。

  農夫約翰希望他的奶牛更加團結,所以他希望任意兩頭牛之間可以交流。他可以買書教他的奶牛任何語言。作為一個相當節儉的農民,FJ想要購買最少的書籍,讓所有他的奶牛互相可以說話。

  幫助他確定:他必須購買的書籍的最低數量。

 

題解:

  並查集。

  將所有有共同語言的牛合併。

  因為當前所有的集合兩兩之間都沒有共同語言,所以每買一本書,只能將其中兩個集合合併。

  所以:最後答案 = 集合個數 - 1

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 10005
 6 #define MAX_M 30005
 7 
 8 using namespace std;
 9 
10 int n,m;
11 int ans=0;
12 int par[MAX_N];
13 int lang[MAX_M];
14 
15 void init_union_find()
16 {
17     for(int i=0;i<n;i++)
18     {
19         par[i]=i;
20     }
21 }
22 
23 int find(int x)
24 {
25     return par[x]==x?x:par[x]=find(par[x]);
26 }
27 
28 void unite(int x,int y)
29 {
30     int px=find(x);
31     int py=find(y);
32     if(px==py) return;
33     par[px]=py;
34 }
35 
36 bool same(int x,int y)
37 {
38     return find(x)==find(y);
39 }
40 
41 void read()
42 {
43     cin>>n>>m;
44     init_union_find();
45     memset(lang,-1,sizeof(lang));
46     int k,l;
47     for(int i=0;i<n;i++)
48     {
49         cin>>k;
50         for(int j=0;j<k;j++)
51         {
52             cin>>l;
53             if(lang[l]!=-1) unite(i,lang[l]);
54             else lang[l]=i;
55         }
56     }
57 }
58 
59 void solve()
60 {
61     for(int i=0;i<n;i++)
62     {
63         if(find(i)==i) ans++;
64     }
65 }
66 
67 void print()
68 {
69     cout<<ans-1<<endl;
70 }
71 
72 int main()
73 {
74     read();
75     solve();
76     print();
77 }

 

相關文章