Codeforces 1383A String Transformation 1|并查集
题意:
有字符串\(A\),\(B\),每次在\(A\)中选取若干个相同的字母(设为\(x\)),改成另一个字母(设为\(y\)),需要满足\(x<y\),问将A改成B的最少操作。
数据范围:
组数t\(1 \le t \le 10\)
字符串长度n \(1 \le n \le 10^5\),保证\(A\),\(B\)长度相等,且所有组数长度不超过\(10^5\)
分析:
从样例看
3
aab
bcc
(aab-bbb-bcc)
本例中,第2个‘a'先转化成’b',再连同’b'转化为‘c'。不难看出减少操作次数可以通过先转化为一个中间的字母,再统一转化为另一字母实现。
抽象成图的形式,即在已有'a->b''b->c'的情况下不加'a->c'边。在这个情况下容易想到并查集维护。易得操作次数增加当且仅当合并两个块。
这样写将无法得出方案,但本题亦未要求,因此可以通过。
最后,无解产生的条件是存在一个\(i\),使\(A_i>B_i\)
#include<bits/stdc++.h>
using namespace std;
int f[30],ans,t,n;string st1,st2;
int fafa(int x)
{
if (f[x]==x) return x;
return f[x]=fafa(f[x]);
}
void hebing(int x,int y)
{
x=fafa(x);y=fafa(y);
if (x!=y)
{
ans++;
f[x]=y;
}
}//并查集模板
int main()
{
cin>>t;
for (int tt=1;tt<=t;tt++)
{
cin>>n;
for (int i=1;i<=26;i++) f[i]=i;
cin>>st1;
cin>>st2;
bool sit=true;ans=0;
for (int i=0;i<n;i++)
{
if (st1[i]>st2[i])
{
cout<<"-1\n";sit=false;
break;
}//无解情况
hebing(st1[i]-'a'+1,st2[i]-'a'+1);//相当于上面的连边
}
if (sit) cout<<ans<<endl;
ans=0;
}
return 0;
}
PS:官方题解与本题解大致相同,不过官方采用的是建边+联通分量,而这里运用并查集,欢迎讨论优劣。