A. String Transformation 1(单向边的并查集)

乍 一 看 像 个 贪 心 乍一看像个贪心

观 察 一 个 这 个 样 例 观察一个这个样例

aab
bcc

由 于 第 一 个 a 要 变 成 b 由于第一个a要变成b ab

第 二 个 a 要 变 成 c 第二个a要变成c ac

第 三 个 b 要 变 成 c 第三个b要变成c bc

按理来说需要操作三次

但 是 由 于 a − > b , b − > c 但是由于a->b,b->c a>b,b>c

所 以 a − > c 的 步 骤 就 不 需 要 了 所以a->c的步骤就不需要了 a>c

也就是说,如果合并的两个字母不在一个集合中,才需要额外操作

但 是 聪 明 的 你 一 定 发 现 并 查 集 要 求 双 向 边 , 但 这 里 是 单 向 边 \color{Red}但是聪明的你一定发现并查集要求双向边,但这里是单向边 ,

比 如 a − b , 那 么 应 该 把 a 和 b 合 并 , 但 是 这 并 不 意 味 着 b 可 以 变 成 a 啊 ! ! 比如a-b,那么应该把a和b合并,但是这并不意味着b可以变成a啊!! ab,ab,ba!!

幸运的是,我们的转换只存在由小字母向大字母转换,b->a是不合法的

综 上 所 诉 , 用 并 查 集 来 维 护 综上所诉,用并查集来维护 ,

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,t,ans,pre[maxn];
char a[maxn],b[maxn];
int find(int x){
	return x==pre[x]?x:pre[x]=find(pre[x]);
}
void join(int q,int w){
	int qq=find(q),ww=find(w);
	if( qq!=ww )
	{
		ans++;
		pre[qq]=ww;
	}
}
int main()
{
	cin >> t ;
	while(t--)
	{
		for(int i=0;i<=20;i++)	pre[i]=i;
		cin >> n >> (a+1) >> (b+1);
		int flag=1;
		ans=0;
		for(int i=1;i<=n;i++)	if( b[i]<a[i] )	flag=0;
		if( !flag )	cout << -1 << endl;
		else
		{
			for(int i=1;i<=n;i++)
				join(a[i]-'a',b[i]-'a');
			cout << ans << endl;
		}
	}
}
/*
aabaf
bccdf

a->b
a->c
b->c*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值