CF1383A String Transformation 1|并查集

链接

题意:

有字符串\(A\)\(B\),每次在\(A\)中选取一部分相同的字母,改成另一个比该字母的字母,问将A改成B的最少步骤

分析:

从样例看

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:官方题解与本题解大致相同,不过官方采用的是建边+联通分量,而这里运用并查集,欢迎讨论优劣。

猜你喜欢

转载自www.cnblogs.com/fmj123/p/13376188.html