标签:scanf 字母 策略 pac put false lang %s amp
题意:一个人有两个字符串A和B,两个字符串具有相同的长度n\((|A| = |B| = n)\),包含前20个小写字符(‘a‘到‘t‘)。每一次操作,这个人可以选择A字符串中字符相同的字母,然后从中选择一些位置,并把这些位置的字母变大。求字符串A变到字符串B的最少操作次数。
分析:我们可以贪心地进行操作,对于"aab"--->"bbc",我们可以先把"aa"变成"bb",那么"aab"--->"bbb",然后把第三个字母‘b‘变成‘c‘,那么‘aab‘--->‘bbc‘。我们可以通过从小到大枚举每个字母,检测字符串A和给定字母是否相同,然后求取对应位置的字母和这个字母相隔的差,在这些差中取最小值,意思是指对于"aabc"--->"bdec",如果枚举到了‘a‘字母,我们可以得到第一个字符串的第一个字母‘a‘和第二个字符串的第一个字母‘b‘的差1,第一个字符串的第二个字母‘a‘和第二个字符串的的第二个字母‘d‘之间的差3,对这个差取最小值,是我们每次要变化的值,对于所有的a,加上这个1,那么‘bbbc‘->‘bdec‘。我们可以通过这个贪心策略,得到最优解。每次枚举的一个字母,都可以把A字符串相同的字母消除掉。所以最多不超过20次。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <algorithm>
using namespace std;
const int N = 100005;
const int inf = 0x3f3f3f3f;
char a[N], b[N];
int len;
int modify(int c)
{
int mn = inf;
for (int i = 1; i <= len; ++i)
{
if (a[i] == b[i]) continue;
if (a[i] - ‘a‘ == c)
{
if (a[i] > b[i]) return -1;
mn = min(mn, b[i] - a[i]);
}
}
for (int i = 1; i <= len; ++i)
{
if (a[i] - ‘a‘ == c)
{
if (a[i] < b[i])
{
a[i] += mn;
}
}
}
//bool flag = true;
if (mn == inf) return 0;
return 1;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
scanf("%s%s", a + 1, b + 1);
len = strlen(a + 1);
bool flag = false;
int res = 0;
//枚举20个字符
for (int i = 0; i < 20; ++i)
{
int g = modify(i);
if (g == -1)
{
flag = true;
break;
}
res += g;
}
if (!flag)
{
printf("%d\n", res);
}
else
{
printf("-1\n");
}
}
return 0;
}
还有一种做法(并查集)
我们可以发现对于"aab"--->"bcc"来说,"aab"先变成"bbb",再变成"bcc","a"--->"b"--->"c",变换的关系具有传递性,我们可以联想到并查集,我们对于要变换的,从a的这个字母向b的这个字母连一条边,b字母向c字母连一条边,如下图,我们可以发现,对于上一题来说,我们用贪心的做法,都是先把相同的字母变到一个字母,然后再变到一个字母,我们每次的变换大小取决于对应位置的字母的最小差值。即并查集中边的条数,等价于连通块个数减-1,相当于2条边,2次操作即可。然后最后我们把所有的连通块里面的边数加起来即可了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <algorithm>
using namespace std;
const int N = 100005;
char a[N], b[N];
int p[N], sz[N];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int i, int j)
{
int pa = find(i);
int pb = find(j);
if (pa != pb)
{
p[pa] = pb;
sz[pb] += sz[pa];
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
scanf("%s%s", a + 1, b + 1);
int len = strlen(a + 1);
for (int i = 1; i <= 20; ++i) p[i] = i, sz[i] = 1;
bool flag = true;
for (int i = 1; i <= len; ++i)
{
if (a[i] != b[i])
{
if (a[i] > b[i])
{
flag = false;
break;
}
merge(a[i] - ‘a‘ + 1, b[i] - ‘a‘ + 1);
}
}
if (!flag)
{
puts("-1");
}
else
{
int res = 0;
for (int i = 1; i <= 20; ++i)
{
int p = find(i);
if (p == i)
{
res += sz[i] - 1;
}
}
printf("%d\n", res);
}
}
return 0;
}
CodeForces 1384C. String Transformation 1(贪心)(并查集)
标签:scanf 字母 策略 pac put false lang %s amp
原文地址:https://www.cnblogs.com/pixel-Teee/p/13381800.html