//本题显然可以用深搜,有几个地方需要注意:1、重叠部分取最小长度,我花费了一次宝贵的下载机会得有一个测试点是2 abababab abababc a,那么第一个单词和第二个单词的重叠部分为ab,而不是ababab,其实想想也是,只有两个单词的重叠部分最小,得到的龙长才会最大;2、每个的单词最多用两次(提示要标记使用次数) ;3、本代码要开O2优化,否则最后一个测试点超时(可能是我的代码不够简洁,qwq!!!)
下面是我AC的代码:
#include
#include
int n, book[100], max, flag; //book数组存储每个单词已使用的次数
char a[100][100], head[100]; //二维数组a存储读取的字符串
int linklen(char s1[], char s2[]) { //判断s2头可以接到s1尾重叠部分的最小长度
int len1 = strlen(s1);
int len2 = strlen(s2);
int i;
for (i = len1 - 1; len1 - i < len2 - 1; i--) { //因为是最小长度,所以i从s1的最后开始遍历,重叠部分长度依次为1,2,3...len2 - 1
int len3 = len1 - i; //len3为可能重叠部分的长度
if (strncmp(s1 + i, s2, len3) == 0) //这里用到了strncmp比较函数,限制了比较的长度,不理解的可自行百度搜索下详细用法,比较结果等于0说明相等
return len3; //有相等的即返回重叠部分的长度
}
return 0; //没有重叠部分即返回0
}
void dfs(char word[], int len) { //深搜部分,word为上一个单词即目前的龙尾,len为目前的龙长
int i, len1, len2;
if (len > max) //更新最大值
max = len;
for (i = 0; i < n; i++) {
len1 = strlen(a[i]);
if (book[i] < 2 && (len2 = linklen(word, a[i]))) { //book[i] < 2说明该单词还有用的机会,len2为重叠长度,前者小于2且后者大于0时才可尝试这个单词
book[i]++; //使用次数+1
dfs(a[i], len + len1 - len2); //继续下一个,以当前单词为尾,此时的龙长是已知长度 + 该单词长度 - 重叠长度
book[i]--; //回溯,恢复原状态
}
}
return;
}
int main() {
int i;
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%s", a[i]); //注:在洛谷上用gets不对,用scanf是可以的
scanf("%s", head); //读入龙头
dfs(head, 1); //以龙头开始,初始长度为1
printf("%d", max); //输出最大值
return 0;
}