1220:单词接龙

【题目描述】
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。

【输入】
输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。

【输出】
只需输出以此字母开头的最长的“龙”的长度。

【输入样例】
5
at
touch
cheat
choose
tact
a
【输出样例】
23

分析

  1. 此题难在字符串的判断与处理上了,我们要找出两个字符串的重叠部分,然后让重叠部分尽量最少,这样拼接出来的长度才能达到最大,更符合题意;
  2. 这题就是最后输入的字符,当做龙头,也就是开头;样例连成的“龙”为 atoucheatactactouchoose。
  3. 每个单词只能用两次,所以我用了一个cnt数组去记录每个单词的使用次数;
  4. 搜索的时候,我们就枚举所有的字符串,看看哪个和当前字符串有重叠部分,然后计算出应该续费上多少个长度(加上新增的长度),把新字符串作为参数继续去搜索。通过check函数去判断两个字符串是否有重叠部分,通过返回值的重叠长度大小即可判断是否重叠;
#include <bits/stdc++.h>

using namespace std;
const int N = 25;

int n, ans = 0;
string str[N];
int cnt[N];//单词使用次数

//求这两个单词的重叠长度
int check(string s1, string s2) {
    //看s2能不能接在s1的屁股后面,也就是:s2单词的头部的部分是s1单词的尾部的部分

    //倒着找到一个重叠肯定就是最优,尽可能让重叠部分很少的两个单词拼接到一块
    for (int i = s1.size() - 1; i >= 0; --i) {
        if (s1[i] == s2[0]) {
            //标记重叠部分在s1开始的索引
            int index = i;
            //找到了可能是重叠部分的头部了,向后扫描
            for (int j = 0; j < s2.size(); ++j) {
                if (s1[index] == s2[j]) index++;
                else break;
            }
            //说明重叠部分相同
            if (index == s1.size()) {
            	//返回重叠部分的长度
                return index - i;
            }
        }
    }

    //这两个单词不可以相连,也就是没有重叠的
    return 0;
}

//s是之前接好的龙,len是当前接龙的总长度
void dfs(string s, int len) {
    ans = max(ans, len);
    //枚举每个单词
    for (int i = 0; i < n; ++i) {
        //第i个单词是否已经使用两次
        if (cnt[i] == 2)
            continue;
        //l为这两个单词重叠的长度
        int l = check(s, str[i]);
        if (l) {
            cnt[i]++;
            //以当前新字符串当结尾开始向后连接
            //len + str[i].size() - l :当前最大长度加上拼接上来的长度(去除重叠)
            dfs(str[i], len + str[i].size() - l);
            cnt[i]--;
        }
    }
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> str[i];
    }
    string start;
    cin >> start;
    dfs(start, 1);
    cout << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上的yyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值