https://www.luogu.com.cn/problem/P1019
这道题好难想,刚开始就字符拼接这块写了一大堆,写完搜索不会写了,光找两个字符串的最小重叠部分就写了好多,最后写不下去了,需要太多代码了,于是就去找大佬题解了,确实自己写繁了,梳理一下大佬的思路吧。
对所有的字符串循环,对于首字母符合条件的以这个字符串开头进行搜索,所以可能搜索不止一次。由于每个字符串最多出现2次,所以用一个标记数组记录某个字符串的使用次数,2次之后就不再使用。
在搜索函数里,难点在于最小重叠部分的寻找,大佬使用了string的成员函数substr,他可以截取字符串的一部分,单参数截取该位置到尾的字符串,双参数前一部分是截取位置,后一部分是截取长度。如果还有疑问可以自己搜一搜。
由于只需要求出最小重叠部分(因为最小重叠才能确保最大长度),所以从上一个字符串的尾部和当前字符串的头部开始检测,如果截取的字符串相等,那就可以拼接,继续下一步搜索。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <iomanip>
using namespace std;
string arr[100];
int vis[100];
char head;
int n,ans;
void dfs(string x,int len) {//x表示上一次连接的字符串,len表示总的字符串长度
ans = max(ans, len);
for (int i = 0; i < n; i++) {
int la = x.length(), lb = arr[i].length();
int p = 1;
while (p < min(la, lb)) {
if (x.substr(la - p) == arr[i].substr(0, p) && vis[i] < 2) {
vis[i]++;
dfs(arr[i], len + lb - p);
vis[i]--;
}
p++;
}
}
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
cin >> n;
for (int i = 0; i < n; i++)cin >> arr[i];
cin >> head;
for (int i = 0; i < n; i++) {//找出以head开头的字符串,符合条件的进行搜索
if (arr[i][0] == head) {
vis[i]++;
dfs(arr[i], arr[i].length());
vis[i]--;
}
}
cout << ans << endl;
return 0;
}