原题链接
看到这道题,我们很容易想到这道题。是的,这道题我们也是将原问题转换成图上问题,将\(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;
}