AtCoder Beginner Contest 399-e

原题链接

看到这道题,我们很容易想到这道题。是的,这道题我们也是将原问题转换成图上问题,将\(s\)字符串中每一个点和\(t\)字符串中所对应的的点之间的关系看成一条有向边,则这个问题就转换成了在一个图上找到一共有几条边,但是这里我们需要注意一个地方,就是如果图中有环,则有几个环我们就要给答案加几(因为如果有环,就不能直接交换,需要将其中一个节点赋成一个新的且没有用过的节点,这样才能保证可以成功交换,而每次赋值都要浪费一次机会,所以最后要给答案加一),这里我们还需要注意一个地方,就是如果图中有基环树(不会基环树的详见这里),就算有环,也不能给答案加一。
因为找到基环树中入度为\(2\)的节点,将它一个在环上的子节点的值改成另一个不在环上的子节点的值,其它点就按正常的方法赋值,这样的话并没有新建节点(因为父节点的两个子节点可以一起赋值,并不用新建节点或者增加步骤),也就不用给答案加一了。注意好所有细节后,我们就可以愉快的写代码了。

CODE

#include<bits/stdc++.h>
using namespace std;
int n,yb[30],fa[30],gs[30],ans=0;
string s,t;
map<char,bool> mp;
bool f[30],fl[30]; 
int main()
{
	memset(yb,-1,sizeof(yb));
	memset(fa,-1,sizeof(fa));
	cin>>n>>s>>t;
    if(s==t) //特判
    {
        cout<<0;
        return 0;
    }
	for(int i=0;i<n;i++)
	{
		if(yb[s[i]-'a']!=-1 && yb[s[i]-'a']!=t[i]-'a') //如果s字符串中两个相同字符所对应的字符不同,则无论怎么交换,都不可能满足条件
		{
			cout<<-1;
			return 0;
		}
		if(yb[s[i]-'a']==-1)
		{
			yb[s[i]-'a']=t[i]-'a'; //赋值
			if(s[i]!=t[i]) fa[s[i]-'a']=t[i]-'a',gs[t[i]-'a']++; //建图
		}
		mp[t[i]]=true;
	}
	for(int i=0;i<26;i++) 
	{
		if(fa[i]!=i && fa[i]!=-1) ans++; //边的个数
	}
	if(mp.size()==26) //特判,因为s中的字符种类一定大于t中的字符种类(若没有,则在上面的特判中就被特判掉了),所以若t中的字符种类满了,且s不等于t,则说明图中存在许多环,且都不是基环树,所以不可能出现新的字符来进行替换,所以不可能。
	{
		cout<<-1<<endl;
		return 0;
	}
	for(int i=0;i<26;i++)
	{
		if(gs[i]>=2) //判断基环树(g代表着每个点的入度)
		{
			if(!f[i])
			{
				int u=i;
				while(u!=-1)
				{
					if(f[u]) break;
					f[u]=true; //标记
					u=fa[u];
				} 
			}
		}
	}
	for(int i=0;i<26;i++)
	{
		if(!f[i]) //统计环的个数
		{ 
			memset(fl,false,sizeof(fl));
			int u=i;
			while(u!=-1)
			{
				if(f[u])
				{
					if(fl[u]) ans++; //累加答案
					break;
				}
				f[u]=fl[u]=true;
				u=fa[u];
			} 
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2025-03-31 21:42  CMY2013  阅读(14)  评论(0)    收藏  举报