005
作者:互联网
题目: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次
,让你组装成一个最长的大字符串(串头给定)
思路简述即为遍历所有字符串,检查使用次数,检查可否拼接,再检查拼接之后的实用性,而后以新串再走一遍
(两步一怀疑,三步一检查,又名盲人电竞题)
标签:string,int,接口,拼接,005,字符串,beginn 来源: https://www.cnblogs.com/a-001/p/15971119.html