洛谷P1019 单词接龙 【深搜】 (C语言 + 详细注释 + 得分点分析)

洛谷P1019 单词接龙 【深搜】 (C语言 + 详细注释 + 得分点分析)_第1张图片

//本题显然可以用深搜,有几个地方需要注意: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;
}

 

 

你可能感兴趣的:(题解,洛谷)