题目描述
小明在太空博物馆发现n个字符串s1,s2,…sn,每个字符串由小写英文字母组成。在一次操作中,他可以选择一个字符串si,抹掉第一个字符并将其附加到字符串的末尾。例如字符串“coolming”,他可以在一次操作中将其转换为字符串“oolmingc”。现在小明想知道:为了将所有字符串变为相同,需要做的最小操作次数是多少?
输入
第一行包含整数n(1 ≤ n ≤ 50)——字符串的数量。之后n行,每行都包含一个字符串。所有字符串的长度相等,不超过50
输出
最小操作的次数,以使所有字符串相等。如果没有解决方案,输出-1。
样例输入
3
abde
bdea
deab
样例输出
3
解题思路
首先对于每个字符串,我们可以构造一个基于第一个字符的循环移位字符串,即将第一个字符移到字符串末尾而得到的字符串。例如,对于字符串“coolming”,我们可以构造如下的循环移位字符串:
coolming
oolmingc
olmingco
lmingcoo
mingcool
ingcoolm
ngcoolmi
gcoolmin
显然,对于每个字符串,我们可以利用如上的方法构造出 n 个循环移位字符串。
然后,我们可以枚举一个基准字符串,假设其为 si,将其转化为 si-0、si-1、si-2、……、si-n-1 这 n 个循环移位字符串。对于每个其它字符串,例如 sj,我们可以在其 n 个循环移位字符串中搜索,找到第一个与 si-0 相同的循环移位字符串,记其为 sj-k,那么将 sj 转化为 sj-k、sj-k+1、sj-k+2、……、sj-k+n-1 这 n 个循环移位字符串所需要的操作数就是 k。
最后,我们求出将所有字符串转化为它们各自的 si-0 所需要的操作数之和,取其中的最小值,即可得到最终的答案。
因此,我们直接双重for循环进行枚举,每次都以第一重for循环的s[i]为基准字符串,计算其他 n - 1个字符串变成基准字符串所需要的操作次数。在每次第二重循环结束之后更新ans值即可。
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
string s[n];
for(int i = 0; i < n; i++) cin >> s[i];
//unordered_map<string, int>mp;
int ans = INT_MAX;
bool flag = false;
for(int i = 0; i < n; i++) {
//mp[s[i]] = 0;
int cnt = 0, res = 0;
for(int j = 0; j < n; j++) {
if(i == j) continue;
int sum = 0;
string str = s[j];
if(str == s[i]) res++;
while(str != s[i]) {
if(str == s[j] && sum != 0) break;
str += str[0];
str = str.erase(0, 1);
sum++;
if(str == s[i]) {
//mp[str] = sum;
res++; // res 用于记录能够经过移动能够和基准字符串s[i]相等的字符串个数
cnt += sum;
}
}
}
if(res == n - 1) {
flag = true; // 存在解决方案
ans = min(ans, cnt);
}
}
if(flag) cout << ans;
else cout << -1;
return 0;
}
/*
3
abde
bdea
deab
*/