题解 P1019 【单词接龙】
单词具体是什么不重要,知道单词间如何转化即可
【分析】
先理清一下题意:
- \(n\)个单词,每个单词限用两次
- 上一个单词能与下一个单词接上,当且仅当上一个单词的末尾 \(k\) 个字符与下一个单词开头的 \(k\) 个字符完全相同
- 给定开头,求最长字符串的长度
我们可以发现,如果我们知道每个单词上一个单词能接哪些单词、下一个单词能接哪些单词、单词的长度,我们接下来的问题都与单词没关系了
同时,假设有两个单词 \(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 【单词接龙】的更多相关文章
- 洛谷 P1019 单词接龙【经典DFS,温习搜索】
		P1019 单词接龙 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在 ... 
- P1019 单词接龙
		单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一 ... 
- 洛谷  P1019 单词接龙 Label:dfs
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ... 
- 洛谷 p1019 单词接龙
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ... 
- P1019 单词接龙   字符串回溯
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ... 
- (洛谷)P1019 单词接龙
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙" ... 
- 洛谷 P1019 单词接龙 (DFS)
		题目传送门 当时一看到这题,蒟蒻的我还以为是DP,结果发现标签是搜索-- 这道题的难点在于思路和预处理,真正的搜索实现起来并不难.我们可以用一个贪心的思路,开一个dic数组记录每个单词的最小重复部分, ... 
- 【搜索】P1019 单词接龙
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ... 
- [NOIP2000] 提高组 洛谷P1019 单词接龙
		题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ... 
- 洛谷——P1019 单词接龙(NOIP2000 T3)
		https://www.luogu.org/problem/show?pid=1019#sub 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母, ... 
随机推荐
- 《新标准C++程序设计》4.5(C++学习笔记15)
			实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back( ... 
- IPv6-isis配置
			①:ipv6 unicast-routing——开启IPv6路由功能 ②:router isis word——开启ISIS进程 ③:is-type——可以修改路由器ISIS等级 ④:进入接口 ⑤:启用 ... 
- tensorflow学习笔记(三)常用函数
			上一篇简单介绍了tensorflow的基本操作,这一篇介绍一些常用的函数. tf.constant() tf.constant ( value , dtype = None , shape = Non ... 
- 050-PHP除法运算
			<?php $n=10/3; //除法运算 echo $n; //输出变量n的值 ?> 
- 127-PHP类通过魔术变量判断类中是否存在指定的方法
			<?php class ren{ //定义人类 //定义成员属性 private $name='Tom'; private $age=15; //定义成员方法 public function g ... 
- 如何有效避免Essay写作抄袭
			每到学期末的时候,各种考试,论文以及作业数不胜数,压得留学党们快要喘不过气了.我想比起写论文,同学们更操心的问题应该是:Plagiarism.要知道在国外Plagiarism的这种行为在学术中是零容忍 ... 
- Centos7.4 Storm2.0.0 + Zookeeper3.5.5 高可用集群搭建
			想了下还是把kafka集群和storm集群分开比较好 集群规划: Nimbus Supervisor storm01 √ √ storm02 √(备份) √ storm03 √ 准备工作 老样子复制三 ... 
- JAVA作用域和排序算法介绍
			一.作用域 1.作用域的概念 所谓的作用域是指引用可以作用到的范围. 一个引用的作用域是从引用定义位置到包裹它的最近的大括号的结束位置.只有在作用域范围内才可以访问到引用,超出作用域无法访问引用. 定 ... 
- assert和hasattr,getattr,setattr
			assert hasattr(self, 'initial_data'), ( 'Cannot call `.is_valid()` as no `data=` keyword argument wa ... 
- 【LeetCode】206. 反转链表
			题目 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶: 你可 ... 
