题目

单词具体是什么不重要,知道单词间如何转化即可


【分析】

先理清一下题意:

  1. \(n\)个单词,每个单词限用两次
  2. 上一个单词能与下一个单词接上,当且仅当上一个单词的末尾 \(k\) 个字符与下一个单词开头的 \(k\) 个字符完全相同
  3. 给定开头,求最长字符串的长度

我们可以发现,如果我们知道每个单词上一个单词能接哪些单词、下一个单词能接哪些单词、单词的长度,我们接下来的问题都与单词没关系了

同时,假设有两个单词 \(W_1\) 与 \(W_2\),长度分别为 \(L_1,L_2\) ,它们之间的公共部分的长度可以是 \(a_1\ ,\ a_2\ ,\ a_3\dots a_m(a_1<a_2<a_3<\dots<a_m)\)

我们要使得总字符串最长,即需要令 \(W_1\) 与 \(W_2\) 的接龙最长

因为它们接龙的长度为 \((L_1+L_2-a_i),1\leq i\leq m\)

所以我们一定要选择最小的 \(a_1\) ,这样才能保证接龙最长


用 \(Len_i\) 表示单词 \(i\) 的长度, \(App_i\) 表示单词 \(i\) 的出现次数

用 \(Con_{i,j}\) 表示单词 \(i\) 后接单词 \(j\) 时它们的最短公共长度

当然,当 \(Con_{i,j}=0\) 时表示单词 \(i\) 后接单词 \(j\) 的最短公共长度为 \(0\) ,即没有公共部分,那么当然 \(i\) 不能后接 \(j\)

我们可以用 string 类来储存各个单词,毕竟 string 作为“合法公民”,可以直接用 “==” 比较是否相同

设我们用 string 类 \(s_i\) 表示第 \(i\) 个单词

根据 string 的自带函数即可轻松完成 \(Len_i,Con_{i,j}\) 的统计:

//统计 Len[i]
for(register int i=1;i<=N;i++) Len[i]=s[i].size();
//统计 Con[i][j]
for(register int i=1,I=d_N;i<=I;i++)//枚举第一个单词
for(register int j=1,J=d_N;j<=J;j++)//枚举第二个单词
for(register int k=1,K=Min(ar_d_Len[i],ar_d_Len[j]),k<=K;k++)//枚举公共长度
if ( s[i].substr(ar_d_Len[i]-k,k)==s[j].substr(0,k) ){
mt_d_Con[i][j]=k;
break;
//第一次找到的公共长度一定最短
} //s.substr(p,l) 表示截取 s ,从第 p 个变量开始的 l 个字符,的字串,返回值为一个 string 变量

开头怎么处理?

很简单,开头视为单词 \(s_0\),照常处理, \(App_0\) 标记为 \(1\) ,代表只能用 \(1\) 次即可

最后,我们深搜的时候直接从 \(s_0\) 开始

每次根据当前第 \(i\) 个单词,枚举 \(Con_{i,j}\neq 0\) 的单词 \(j\) ,长度增加 \((Len_j-Con_{i,j})\) 即可


【代码】

那本蒟蒻就放 我码风极丑的 代码了

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
using namespace std;
#define f(a,b,c,d) for(register int a=b,c=d;a<=c;a++)
#define g(a,b,c,d) for(register int a=b,c=d;a>=c;a--)
typedef int i32;
typedef unsigned int u32;
typedef long long int i64;
typedef unsigned long long int u64; inline i32 Min(i32 a,i32 b) { return (a<b)?a:b; }
inline i32 Max(i32 a,i32 b) { return (a>b)?a:b; } i32 d_N,ar_d_App[32]={0},ar_d_Len[32]={0},mt_d_Con[32][32]={0}; inline bool alw(char c) { return (c!='\n')&&(c!='\r'); } inline void getstring(string &s){
string t;
getline(cin,t);
if( !alw(t[ t.size()-1 ]) ) s=t.substr(0, t.size()-1 );
else s=t;
} inline i32 input(){
scanf("%d\n",&d_N);
string s[32];
f(i,1,I,d_N) getstring(s[i]);
getstring(s[0]); f(i,0,I,d_N) ar_d_Len[i]=s[i].size(); //i->j
f(i,0,I,d_N)
f(j,1,J,d_N)
f(k,1,K,Min(ar_d_Len[i],ar_d_Len[j]))
if ( s[i].substr(ar_d_Len[i]-k,k)==s[j].substr(0,k) ){
mt_d_Con[i][j]=k;
break;
} ar_d_App[0]=1;
return s[0].size();
} i32 dfs(i32 d_P){
ar_d_App[d_P]++;
i32 d_Ans=0;
f(i,1,I,d_N) if(mt_d_Con[d_P][i]>0&&ar_d_App[i]<2){
i32 d_Tmp=dfs(i)+ar_d_Len[i]-mt_d_Con[d_P][i];
d_Ans=Max(d_Ans,d_Tmp);
}
ar_d_App[d_P]--;
return d_Ans;
} int main(){
i32 d_Ans=input();
cout<<dfs(0)+d_Ans;
return 0;
}

最后安利一下 本蒟蒻的博客

题解 P1019 【单词接龙】的更多相关文章

  1. 洛谷 P1019 单词接龙【经典DFS,温习搜索】

    P1019 单词接龙 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在 ...

  2. P1019 单词接龙

    单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一 ...

  3. 洛谷 P1019 单词接龙 Label:dfs

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  4. 洛谷 p1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  5. P1019 单词接龙 字符串回溯

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  6. (洛谷)P1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙" ...

  7. 洛谷 P1019 单词接龙 (DFS)

    题目传送门 当时一看到这题,蒟蒻的我还以为是DP,结果发现标签是搜索-- 这道题的难点在于思路和预处理,真正的搜索实现起来并不难.我们可以用一个贪心的思路,开一个dic数组记录每个单词的最小重复部分, ...

  8. 【搜索】P1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  9. [NOIP2000] 提高组 洛谷P1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  10. 洛谷——P1019 单词接龙(NOIP2000 T3)

    https://www.luogu.org/problem/show?pid=1019#sub 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母, ...

随机推荐

  1. Google的搜索API的Delphi封装

    这个东西实现了已经有一段时间了,那个时候谷歌还没有退出中国内地呢!而现在呢,谷歌都退了有一些日子了!紧以此纪念一番! 话说谷歌API,我相信很多人应该都知道!不晓得在实际应用中,用的人多不多(我说的不 ...

  2. 解决oracle 11g 导出空表的方法

    ORACLE 11G中有个新特性,当表无数据时,不分配segment,以节省空间. 解决方法: 1)insert一行,再rollback就产生segment了 该方法是在在空表中插入数据,再删除,则产 ...

  3. Qt编写的项目作品2-控件属性设计器(组态)

    一.功能特点 自动加载插件文件中的所有控件生成列表,默认自带的控件超过120个. 拖曳到画布自动生成对应的控件,所见即所得. 右侧中文属性栏,改变对应的属性立即应用到对应选中控件,直观简洁,非常适合小 ...

  4. Java 用户输入

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...

  5. mpvue + Vant weapp + 微信云服务 打造小程序应用

    写在前面的话: 从事小程序开发已经大半年的时间了,但是一直都是再用原生写项目.一直想着用框架自己写一个小程序,但苦于一直没有时间.正好最近项目搁置,有了空闲时间,就研究了下mpvue + Vant w ...

  6. LeetCode1217 玩筹码(贪心)

    题目: 数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中. 你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以): 将第 i 个筹码向左或者右移动 2 个单位,代价为 ...

  7. SQL注入过WAF(11.4 第三十三天)

    WAF是什么? Web应用防护系统(也称:网站应用级入侵防御系统.英文:Web Application Firewall,简称: WAF).也叫Web防火墙,主要是对Web特有入侵方式的加强防护,如D ...

  8. java 循环节长度

    循环节长度 两个整数做除法,有时会产生循环小数,其循环部分称为:循环节. 比如,11/13=6=>0.846153846153- 其循环节为[846153] 共有6位. 下面的方法,可以求出循环 ...

  9. UVA - 679 Dropping Balls(二叉树的编号)

    题意:二叉树按层次遍历从1开始标号,所有叶子结点深度相同,每个结点开关初始状态皆为关闭,小球从根结点开始下落(小球落在结点开关上会使结点开关状态改变),若结点开关关闭,则小球往左走,否则往右走,给定二 ...

  10. laravel.url

    通过php artisan route:list 可以看到当前应用的路由情况, 在前端页面中如果要修改一个实体,需要用到实体.update,涉及的uri为实体/{实体},所用的http方法为put. ...