题目:https://www.luogu.com.cn/problem/P1019
思路:数据范围20,搜索没跑了
对于每个单词使用次数这里,可以定义一个数组存(但是判断是否用过两次千万不要手贱写成 >2 ,这是我做题时的槽点之一)
处理的重难点是在接口这一块
检查:既然要最长,那肯定是龙尾和接头对比
假定一个接口长度,然后用一个函数进行检查
一个字符一个字符的比,有一个对不上直接驳回
以s为龙,m为接串,l为s的长度,k为假定接口长度,则有
if(s[l-k+j]!=m[j]){
return 0;
}循环着来就能遍历整个接口
紧接着,如果一个接完了的字符串甚至比原来的还小或是与原来的相等,那这次拼接不仅无意义,还浪费了一个单词,所以遇到这类情况直接跳过,不要在费时间搜这个分支了
还有,字符串改完了之后,即便无意义也无法再回溯,所以要保证上一步的字符串存在,换句话说就是做个龙傀儡,让他先上去吃伤害,确认安全了再把龙真身放出去
拼接与检查长的差不多,具体就别看思路了,看代码吧
但是!在拼接时记得带取址符,不然更改只会在函数里生效,就出不去了(我的槽点之二)
#include<bits/stdc++.h>
using namespace std;
int n,i,ans=0;string beginn;
int f[21];string s[21];
//以上均为常规操作
//但注意beginn是后面需要跟一串字符的龙头
//所以定义为string类型
bool o(string b,string m,int k){
//b是当前的龙,m是将要拼接的串,k为接口长度
int l=b.size(),j;
for(j=0;j<k;++j){//极限拉扯(验证是否能拼接)
if(b[l-k+j]!=m[j]){//拉折了
return 0;//慢走不送
}
}
return 1;
}
void in(string &b,string m,int k){//接
//注意!!!!!!!!!!!!!!
//这里的拼接是要对全局的龙使用的
//不带&(取址符)意味着你的龙只在函数里更改过
//对整条龙没有任何影响
int l=m.size(),j;
for(j=k;j<l;++j){//从接口尾到串尾
b+=m[j];//极限摆头
//c++智能到可以直接用+=在字符串尾加字符
}
}
void dfs(string b){
int l=b.size();//每次拿到一条新龙
ans=max(ans,l);//都要跟原来的比比
int j,k,x;string b1;//备用
for(j=1;j<=n;++j){//一串一串来
if(f[j]>=2){//用过两遍的串不能再用了
continue;//再见
}
//如果能用
x=s[j].size();//接串的长度
for(k=1;k<x;++k){//枚举接口长度
if(o(b,s[j],k)){//可以接
b1=b;
//重点 !!!!!!!!!!
//这条龙在之后的循环还要用
//所以用字符串副本进行拼接
in(b1,s[j],k);//接
if(b1==b){//接完了,没啥改变
continue;//那还用个屁,扔了吧
}
//有改变了
f[j]++;//使用次数+1
dfs(b1);//继续搜
f[j]--;//继续跟他拉扯
}
}
}
}
int main(){
//以下常规
scanf("%d",&n);
for(i=1;i<=n;++i){
cin>>s[i];
}
cin>>beginn;
//以上常规
dfs(beginn);
printf("%d",ans);
return 0;
}
题目总结:给你n个字符串,每个字符串可以用2次
,让你组装成一个最长的大字符串(串头给定)
思路简述即为遍历所有字符串,检查使用次数,检查可否拼接,再检查拼接之后的实用性,而后以新串再走一遍
(两步一怀疑,三步一检查,又名盲人电竞题)
浙公网安备 33010602011771号