题意:给出两个由小写字母构成的长度相等的字符串$S$与$T$,给出变换$c1\,c2$表示将两个字符串中所有$c1$字符变为$c2$,求将$S$和$T$通过这种变换变为相等字符串的最少变换次数。$1 \leq |S|,|T| \leq 10^5$
很巧妙的思维诶qwq
用并查集维护变换过程,同一个并查集内的所有字符都能通过若干变换表示为同一个字符,而不同并查集内的字符通过变换无法变为同一字符。考虑同一个位置上的两个字符$S_a$与$T_a$,如果它们不相等,那么这两种字符之间就一定要经过直接或者间接的变换变到一起,也就是说它们要在同一个并查集内,如果不在就需要连边并增加一种变换,如果在同一并查集内那么表示已经间接地通过之前的变换使得这两个字符相等了,就不需要再变换了。
1 #include<bits/stdc++.h> 2 //This code is written by Itst 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 bool f = 0; 8 char c = getchar(); 9 while(c != EOF && !isdigit(c)){ 10 if(c == '-') 11 f = 1; 12 c = getchar(); 13 } 14 while(c != EOF && isdigit(c)){ 15 a = (a << 3) + (a << 1) + (c ^ '0'); 16 c = getchar(); 17 } 18 return f ? -a : a; 19 } 20 21 const int MAXN = 100010; 22 char c[25][2] , s1[MAXN] , s2[MAXN]; 23 int fa[27]; 24 25 int find(int x){ 26 return fa[x] == x ? x : (fa[x] = find(fa[x])); 27 } 28 29 int main(){ 30 #ifndef ONLINE_JUDGE 31 freopen("939D.in" , "r" , stdin); 32 //freopen("939D.out" , "w" , stdout); 33 #endif 34 int N = read(); 35 int cnt = 0; 36 scanf("%s%s" , s1 + 1 , s2 + 1); 37 for(int i = 1 ; i <= 26 ; ++i) 38 fa[i] = i; 39 for(int i = 1 ; i <= N ; ++i) 40 if(find(s1[i] - 'a') != find(s2[i] - 'a')){ 41 c[++cnt][0] = find(s1[i] - 'a') + 'a'; 42 c[cnt][1] = find(s2[i] - 'a') + 'a'; 43 fa[find(s1[i] - 'a')] = find(s2[i] - 'a'); 44 } 45 cout << cnt << endl; 46 for(int i = 1 ; i <= cnt ; ++i) 47 cout << c[i][0] << ' ' << c[i][1] << endl; 48 return 0; 49 }