P1019 [NOIP2000 提高组] 单词接龙 - 洛谷 | 计算机科学教育新生态
题目来源
洛谷
题目内容
[NOIP2000 提高组] 单词接龙
题目背景
注意:本题为上古 NOIP 原题,不保证存在靠谱的做法能通过该数据范围下的所有数据。
本题为搜索题,本题不接受 hack 数据。关于此类题目的详细内容
NOIP2000 提高组 T3
题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast
和 astonish
,如果接成一条龙则变为 beastonish
,另外相邻的两部分不能存在包含关系,例如 at
和 atide
间不能相连。
输入格式
输入的第一行为一个单独的整数 n n n 表示单词数,以下 n n n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出格式
只需输出以此字母开头的最长的 “龙” 的长度。
样例 #1
样例输入 #1
5
at
touch
cheat
choose
tact
a
样例输出 #1
23
提示
样例解释:连成的“龙”为 atoucheatactactouchoose
。
n ≤ 20 n \le 20 n≤20。
知识点
dfs递归 搜索回溯 字符串
题目思路
- 首先要 dfs 递归搜索来拼接字符串
- 用一个数组记录使用过的字符串的次数,根据题目要求最多可以用两次 , 不必用完所有字符串
- 计算要拼接的两个字符串之间的公共子串长度
就是计算他们相同的部分字符串长度是多少,而且不能互相包含,包含了拼接起来就是取长的那条(没意义)
AC代码
//
// Created by Jisam on 2024/7/1.
//
#include <bits/stdc++.h>
// 定义一个长整型别名,用于处理大数情况
#define i64 long long
// 使用标准库命名空间,方便调用各种标准函数和容器
using namespace std;
// 定义常量MAXN,用于限制字符串数组的最大长度
const int MAXN = 20 + 5;
// 定义全局变量,用于存储中间计算结果和输入数据
int n, maxLen;
string words[MAXN], str;
int used[MAXN];
/**
* 计算两个字符串s1和s2的最长公共后缀长度
* @param s1 第一个字符串
* @param s2 第二个字符串
* @return 返回最长公共后缀的长度
*/
int calc(string s1, string s2) {
// 从后向前遍历s1,寻找与s2匹配的最长后缀
for (int i = s1.size(); i >= 0; i--) {
if (s1[i] == s2[0]) {
int l = i;
// 遍历s2,检查是否为s1的后缀
for (int j = 0; j < s2.length(); j++) {
if (s1[l] == s2[j]) {
l++;
} else {
// 不匹配时退出循环
break;
}
}
// 如果l等于s1的长度,说明s2是s1的后缀
if (l == s1.size()) {
return l - i;
}
}
}
// 未找到匹配后缀,返回0
return 0;
}
/**
* 深度优先搜索函数,用于寻找最长的特殊字符串
* @param sumSameLen 当前已累计的相同后缀长度
* @param x 当前构建的特殊字符串
*/
void dfs(int sumSameLen, string x) {
// 更新最长特殊字符串的长度
maxLen = max(maxLen, (int)x.size() - sumSameLen);
// 遍历所有可能的单词
for (int i = 1; i <= n; i++) {
int sameLen = 0;
// 如果当前单词已使用两次,则跳过
if (used[i] >= 2) {
continue;
}
// 计算当前单词与x的最长公共后缀长度
sameLen = calc(x, words[i]);
// 如果没有公共后缀,跳过
if (!sameLen) {
continue;
}
// 标记当前单词为已使用
used[i]++;
// 递归调用,尝试将当前单词添加到特殊字符串中
dfs(sumSameLen + sameLen, x + words[i]);
// 回溯,撤销当前单词的使用标记
used[i]--;
}
return;
}
int main() {
// 关闭同步标准输入输出与C风格输入输出,提高性能
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 输入单词数量和各个单词
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> words[i];
}
// 输入特殊字符串
cin >> str;
// 调用深度优先搜索函数,开始寻找最长特殊字符串
dfs(0, str);
// 输出结果
cout << maxLen;
return 0
}