题意:给两个字符串 a ,b 每次你可以把 a 中所有 相同的字符换成比它大的一个任何字符 ,问最少多少次操作可以把 a 变成 b
题解:比赛的时候发现其实字符串的改变具有传递性,比如a-b-c,那a-c就没必要了,a-b-c-d同理我们其实只变三次就行a直接传递过去,不过比赛的时候并没有反应过来这是个并查集,后来看题解才发现这不就是连通块内点的个数减一么,直接用并查集解决就行了。
AC代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int f[maxn],num[maxn];
int find_x(int x){
if(f[x]!=x)return f[x]=find_x(f[x]);
else return f[x];
}
void unite(int x,int y){
int aa=find_x(x);
int bb=find_x(y);
if(aa!=bb){
f[aa]=bb;
num[aa]+=num[bb];
}
}
main(){
IOS;
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<=30;i++)f[i]=i,num[i]=1;
string a,b;
cin>>a>>b;
int flag=0;
for(int i=0;i<a.size();i++){
if(a[i]!=b[i]){
if(a[i]>b[i])flag=1;
else unite(a[i]-'a'+1,b[i]-'a'+1);
}
}
if(flag){
cout<<-1<<endl;
continue;
}
int ans=0;
for(int i=0;i<=30;i++)find_x(i);
for(int i=0;i<=30;i++){
//if(f[i]==i)
ans+=num[i]-1;
//if(num[i]>1)cout<<f[i]<<" "<<i<<" "<<num[i]<<endl;
}
cout<<ans<<endl;
}
}