DFS - 单词接龙

单词接龙

问题描述:

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 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
    }
}



【代码来源于网络,由于时间久远已经找不到原地址,在此致歉。仅作个人学习用,如有侵权我会删除】


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值