题目链接:https://codeforces.com/contest/1263/problem/D
题意:有n个小写字符串代表n个密码,加入存在两个密码有共同的字母,那么说这两个密码可以认为是同一个集合,可以互相破解,先求有多少个不同集合的密码
思路:简单的并查集。首先一共有26个字母,对于每个密码,我们合并其所涵盖的字母,例如密码1:abcd,那么abcd合并起来,含有abcd的任意密码都同属于一个集合,所有我们把n个密码串先做一次合并。最终再扫一遍所有的密码串,用set维护集合的个数,最终输出set集合的大小即可。
代码:
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<set> 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 typedef long long ll; 10 const int maxn =2e5+10; 11 int fa[30]; 12 void init(){ 13 for(int i = 1;i<=26;i++){ 14 fa[i] = i; 15 } 16 } 17 int find(int x){ 18 if(fa[x] == x) return x; 19 else return fa[x] = find(fa[x]); 20 } 21 void unite(int x,int y){ 22 int tx = find(x),ty = find(y); 23 if(tx == ty) return ; 24 fa[y] = tx; 25 } 26 int main(){ 27 ios::sync_with_stdio(false); 28 cin.tie(0); 29 cout.tie(0); 30 int n; 31 cin>>n; 32 init(); 33 set<int> ss; 34 vector<string> v; 35 while(n--){ 36 string s; 37 cin>>s; 38 v.push_back(s); 39 int t = s[0]-'a'+1; 40 for(int i = 0;i<s.length() ;i++){ 41 int cur = s[i]-'a'+1; 42 unite(t,cur);//合并当前字符串的所有字母 43 } 44 } 45 for(int i = 0;i<v.size() ;i++){ 46 for(int j =0;j<v[i].length();j++){ 47 ss.insert(find(v[i][j]-'a'+1));//扫所有字符串的所有字母,判断是否是同一父亲 48 } 49 } 50 cout<<ss.size(); 51 return 0; 52 }