做好当前吧,抱怨和祈求怜悯没有任何作用,你不是来作秀的!
题目地址
又是一道好的题目(其实是因为我菜。。),cf 真的是个好东西。
思路:
首先先判断无解的情况:这个很好的判断。
然后是有解的思路:看成一个图论的问题,我们将字符串
a
a
a和字符串
b
b
b不相同的点之间建一条边,我们可以想一下假设我们需要
a
[
i
]
−
>
b
[
i
]
,
a
[
j
]
−
>
b
[
j
]
a[i] ->b[i], a[j] -> b[j]
a[i]−>b[i],a[j]−>b[j],并且我们如果
b
[
j
]
=
=
b
[
i
]
b[j] == b[i]
b[j]==b[i],那么我们就可以考虑先将
a
[
i
]
−
>
a
[
j
]
(
a
[
i
]
<
a
[
j
]
)
a[i] - > a[j] (a[i] <a[j])
a[i]−>a[j](a[i]<a[j]),这样做的话我们就可以顺带的将图中
a
[
i
]
−
>
a
[
j
]
a[i] -> a[j]
a[i]−>a[j]的边完成并且不需要消耗多余的步数,我们发现这样是拓扑序,即:处在前边的点都可以向后边进行延伸,我们每次向这个拓扑序中加一个点都需要最小耗费一个步数,加入的点可以按照字典序进行连边,当然在图中我们可能存在所有的点不在一个联通块的情况,所以我们需要判断一下,假设我们只有一个连通块,那么我只需要加入
(
n
−
1
)
(n - 1)
(n−1)次边,假设我们有两个连通块那么我们就需要加入
(
n
−
2
)
(n - 2)
(n−2)条边,以此类推。
#include <iostream>
#include <cstring>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int N = 20;
int a, b, c;
int map[N][N];
bool vis[N];
void dfs (int u)
{
vis[u] = true;
for (int i = 0; i < 20; i ++)
if (map[u][i] && !vis[i]) dfs (i);
}
int main()
{
int T; scanf ("%d", &T);
while (T --)
{
int n; string a, b; cin >> n >> a >> b;
memset (vis, 0, sizeof vis);
memset (map, 0, sizeof map);
bool flag = true;
for (int i = 0; i < n; i ++) // have a
if (a[i] > b[i]) flag = false;
else map[a[i] - 'a'][b[i] - 'a'] = true, map[b[i] - 'a'][a[i] - 'a'] = true;
if (!flag)
{
puts ("-1");
continue;
}
int res = 20;
for (int i = 0; i < 20; i ++)
if (!vis[i]) dfs (i), res --;
printf ("%d\n", res);
}
return 0;
}