专栏文章
题解五:P1019 [NOIP 2000 提高组] 单词接龙
P1019题解参与者 11已保存评论 15
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 15 条
- 当前快照
- 1 份
- 快照标识符
- @miq6ss9f
- 此快照首次捕获于
- 2025/12/03 23:53 3 个月前
- 此快照最后确认于
- 2025/12/03 23:53 3 个月前
题目传送门:P1019 [NOIP 2000 提高组] 单词接龙。
2025.8.11 第一次修改:调整部分排版;更改、增加一些内容;修改两处笔误。
题意
给出 ,给出 个单词,给出一个字符 ,将单词连接成一个长度为 且以字符 开头的字符串,使得 尽可能大,输出 。
连接时要注意:
- 每个单词最多使用两次;
- 第一个单词要以 开头;
- 后一个单词的开头部分应与前一个单词的结尾部分相同(也就是题目中所说的“重合部分”);
- 应保证重合部分的长度最多必须小于这两个单词的长度。或者说,两个单词不能互相包含(否则连接没有意义);
- 连接后,重合的部分会被覆盖。
思路
搜索。
我们依次枚举所有可能的排列情况,每一次都更新最大长度 ,最后输出。
首先,我们需要一个函数,得到已有的总字符串和新加入的单词的重合部分长度大小(有几位是重合的)。如果这个长度为 ,说明这个单词不能被添加(没有重合部分)。显然,为了使总长度尽可能长,这个连接部分要尽可能小,所以我们从小开始枚举。
CPPll check(string s1,string s2){
ll num=min(s1.size(),s2.size());
for(ll i=1;i<num;i++){//枚举可能的长度
bool f=true;//用来判断
for(ll j=0;j<i;j++)//对比每一位
if(s1[s1.size()-i+j]!=s2[j]){
f=false;//如果不相同则判断为否
break;
}
if(f==true) return i;//如果判断为正,返回重合部分的长度
}return 0;//否则说明不能被添加
}
关于高亮行
注意这一行的判断:
CPPif(s1[s1.size()-i+j]!=s2[j])
这里
s1.size() 是字符串的长度,s1.size()-i 是字符串倒数第 位,也对应新单词的第 位,所以字符串的第 s1.size()-i+j 位就对应单词的第 位。我们判断字符串的后 位和单词的前 位是否不同,就要依次判断字符串的倒数第 位至最后一位与单词的第一位至第 位是否不同。即对于 ,执行上面的语句判断。对于搜索部分,我们依次枚举单词,判断是否能在总字符串后面添加。如果不行,则直接进行下一次循环;否则添加新单词,递归,回溯,再进行下一次循环。当然,如果这个单词已经使用过两次,也直接进行下一次循环。
CPPvoid dfs(string st,ll num){//num 是当前总字符串的长度
len=max(num,len);//更新最大长度
for(ll i=0;i<n;i++){//枚举单词
if(a[i]>=2) continue;//判断这个单词使用次数
ll m=check(st,str[i]);//记录重合部分长度
if(m>0){//如果重合长度大于 0,也就是说可以被添加
a[i]++;//增加单词使用次数
dfs(str[i],num+str[i].size()-m);//递归
a[i]--;//回溯
}//否则代表没有重合,不操作
}return;
}
关于
要强调的是, 是最近添加的单词,而不是总的字符串。我们前面使用函数计算重合部分长度时,应保证该长度小于前后两个单词的长度。而如果使用总字符串,无法确定上一个单词从哪里开始。(当然,你要是不嫌麻烦也可以再开一个变量存储上一个单词的长度。)
代码实现
刚才思路部分已经给出了主要代码,此处只做必要标记。
CPP// 24ms / 1.04MB / 678B C++98 O2
// 24ms / 816.00KB / 678B C++98
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[20],len,n;//a记录每个单词使用次数
string str[20];//记录每个单词
ll check(string s1,string s2){
ll num=min(s1.size(),s2.size());
for(ll i=1;i<num;i++){
bool f=true;
for(ll j=0;j<i;j++)
if(s1[s1.size()-i+j]!=s2[j]){
f=false;
break;
}
if(f==true) return i;
}return 0;
}
void dfs(string st,ll num){
len=max(num,len);
for(ll i=0;i<n;i++){
if(a[i]>=2) continue;
ll m=check(st,str[i]);
if(m>0){
a[i]++;
dfs(str[i],num+str[i].size()-m);
a[i]--;
}
}return;
}
int main(){
cin>>n;
for(ll i=0;i<=n;i++)
cin>>str[i];//特别强调:这里把最后输入的首字母作为单词中的一个输入
dfs(' '+str[n],1);
cout<<len;
return 0;
}
相关推荐
评论
共 15 条评论,欢迎与作者交流。
正在加载评论...