Codeforces Round #659 (Div. 2)1384C String Transformation 1(并查集,好题)

题意:给两个字符串 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;
	} 
}

猜你喜欢

转载自blog.csdn.net/Alanrookie/article/details/107575499