其他分享
首页 > 其他分享> > 005

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