单词接龙
问题描述:
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。
输入格式:
输入的第一行为一个单独的整数n (n<=20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式:
只需输出以此字母开头的最长的“龙”的长度
样例输入:
5
at
touch
cheat
choose
tact
a
样例输出:
23
样例说明:
连成的“龙”为atoucheatactactouchoose
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char str[25][10];
int map[25][25];
int n, visited[25], max_sum;
int length[25];
void init();
void dfs(int i, int v);
int change(char str1[], char str2[]);
int main(){
int i, j;
int len1, len2, num, front, end, sum = 0;
char ch;
scanf("%d", &n);
for(i = 0; i < n; i++){
scanf("%s", str[i]); //将输入的单词以字符串存储在str中
length[i] = strlen(str[i]);//将每个单词的长度 存储在length数组中,编号即为输入顺序
}
scanf(" %c", &ch);//得到开头的字符
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
map[i][j] = change(str[i], str[j]);//将各个单词之间的关系以邻接矩阵来表示,其中[i][j]表示从i到j的关系 ,值为重合的长度
}
}
for(i = 0; i < n; i++){
if(str[i][0] == 'a'){//找到满足作为【头】条件的单词
init();//初始化已访问记录数组
max_sum = 0;//初始化当前最大值为零
dfs(0, length[0]);//开始深度搜索可行方案,输入参数为第i个单词与第i个单词的长度
if(sum < max_sum){
sum = max_sum; //此处为局部变量与全局变量的巧妙应用,此处 sum才是记录最大值,而 max_sum是当前最大值
}
}
}
printf("%d\n", sum);
}
int change(char str1[], char str2[]){//str1与str2的关系,返回值为重合部分的长度
int i, j;
int len1 = strlen(str1), len2 = strlen(str2);//存储两个字符串的长度
int front1, front2;
for(i = 0; i < len1; i++){
front1 = i; front2 = 0;
len2 = strlen(str2);
while(str1[front1] == str2[front2] && str1[front1] && str2[front2]){//重合则往后退一个
front1 ++; front2++;
}
if(front1 == len1 && i == 0){//str1包含于str2,不符合要求则重合部分为零
return 0;
}
else if(front1 == len1 && front2 == len2){//str2包含于str1,不符合要求则重合部分为零
return 0;
}
else if(front1 == len1 && i != 0 && front2 != len2){//有关系,返回重合长度
return (len1 - i);
}
}
return 0;//无重合部分,无关系
}
void dfs(int v, int sum){//输入的参数为当前的单词序号以及当前单词序号下可行的【龙】的长度
int i, var;
if(sum > max_sum){//如果当前龙长度大于记录中的龙长度,则更新记录
max_sum = sum;
}
for(i = 0; i < n; i++){
if(map[v][i] != 0 && visited[i] > 0){//如果存在关系且未被访问过
visited[i]--;//访问一次
dfs(i, sum + length[i] - map[v][i]);//深度遍历其子树
visited[i]++;//子树遍历完毕,恢复为访问前状态
}
}
}
void init(){
int i;
for(i = 0; i <= n; i++){
visited[i] = 2;//由于每个单词可出现两次,所以初始化为2
}
}
【代码来源于网络,由于时间久远已经找不到原地址,在此致歉。仅作个人学习用,如有侵权我会删除】