前言

首先,看到这道题目,我首先想到的是暴搜,通过\(vector\)来搞,代码也是很短的。

这里用了一个类似于分治的思想

把一个大问题转化为小问题

先枚举第一个单词,之后把能拼接在它后面的单词都一个一个的去试,哪个最优选哪个

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T&x){
T f=1;x=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
x*=f;
}//快读,常数优化
template<typename T>inline void write(T x){
if(x<0){
putchar('-');
write(x*-1);
return;
}
if(x>9)write(x/10);
putchar(x%10+48);
}//快写,常数优化
string st[18];
vector<int>v[210];//动态数组
int f[18];//标记数组
int dfs(int x){
int ans=0;
for(auto i:v[st[x][st[x].size()-1]])//v数组是存第1个字母的一个容器
if(!f[i]){
f[i]=1;//标记这个字符串已经用过了
ans=max(ans,dfs(i));//打擂
f[i]=0;//回溯
}
return ans+st[x].size();
}
int main(){
int ans=0,n;
read(n);//读入
for(int i=1;i<=n;i++)cin>>st[i],v[st[i][0]].push_back(i);//读入,放入vector容器
for(int i=1;i<=n;i++){
f[i]=1;//表记
ans=max(ans,dfs(i));//打擂法找到最优解
f[i]=0;//回溯
}
write(ans);//输出
return 0;
}

然后,你会发现你只得了70分,开\(O(2)\)试试?TLEagain!

想一想更优秀的算法,加记忆化?是的!

正文

储存状态

如何存状态

我们发现每一个字符串的状态都要么是0,要么是1,所以我们可以用二进制的思想去压缩状态。

\[1≤N≤16
\]

\[2^{n(16)}=65536
\]

开数组很充裕,浪费也不要紧。

判断状态

如何去判断第\(i\)个单词有没有用过

从右往左这个数二进制的第\(i\)位是\(1\),就代表这个单词用过,反之\(0\)就代表这个单词没用过。

但给你这么一个数,你该这么去判断呢?

用位运算!

如果第\(i\)为是\(1\),那么\(x>>(i-1)\)后\(\mod2\)就是\(1\)

如果第\(i\)为是\(0\),那么\(x>>(i-1)\)后\(\mod2\)就是\(0\)

那么判断这个单词是否用过,我们就可以这么写

if(!((y>>(i-1)&1))//按位与,只有两个数这一位都是1才为1,所以只有当最后一位是1,这个数才会是1,否则是0

标记状态

如何将这一位变成\(1\)

将这一位变成\(1\),我们可以用位运算中的按位或——两位都是\(0\),这一位的得数才为\(0\)

y|(1<<(i-1))

这应该是很显然的

总结

现在就可以看总的代码了

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T&x){
T f=1;x=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
x*=f;
}
template<typename T>inline void write(T x){
if(x<0){
putchar('-');
write(x*-1);
return;
}
if(x>9)write(x/10);
putchar(x%10+48);
}
string st[18];
vector<int>v[210];
int f[17][1<<17];
int dfs(int x,int y){
if(f[x][y])return f[x][y];
int ans=0;
for(auto i:v[st[x][st[x].size()-1]])
if(!((y>>(i-1))&1))ans=max(ans,dfs(i,y|(1<<(i-1))));
return f[x][y]=ans+st[x].size();
}
int main(){
int ans=0,n;
read(n);
for(int i=1;i<=n;i++)cin>>st[i],v[st[i][0]].push_back(i);
for(int i=1;i<=n;i++)ans=max(ans,dfs(i,(1<<(i-1))));
write(ans);
return 0;
}

刚开始我认为这应该没有多少重复运算,所以我写了个暴搜,但是,我写了记忆化之后惊奇地发现,暴搜总用时\(4.00s\),也就是\(4000ms\),而记忆化搜索总用时\(73ms\),快了不只一点。但是空间确实消耗很大。

编程中有很多算法,用空间换时间,记忆化搜索就是这么一个代表,我们要学习这种思想,想出更巧妙的办法!

题解 P1278 【单词游戏】的更多相关文章

  1. 洛谷 P1278 单词游戏

    P1278 单词游戏 题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单 ...

  2. Luogu P1278 单词游戏(dfs)

    P1278 单词游戏 题意 题目描述 \(Io\)和\(Ao\)在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何 ...

  3. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  4. P1278 单词游戏

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  5. [洛谷P1278]单词游戏

    题目大意:给一个有$n(n\leqslant16)$个单词的字典,求单词接龙的最大长度 题解:发现$n$很小,可以状压,令$f_{i,j}$表示选的数的状态为$i$,最后一个字母是$j$的最大长度. ...

  6. LUOGU 1278 单词游戏

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  7. 【题解】JXOI2018游戏(组合数)

    [题解]JXOI2018游戏(组合数) 题目大意 对于\([l,r]\)中的数,你有一种操作,就是删除一个数及其所有倍数.问你删除所有数的所有方案的步数之和. 由于这里是简化题意,有一个东西没有提到: ...

  8. LOJ#10106. 「一本通 3.7 例 2」单词游戏

    题目链接:https://loj.ac/problem/10106 题目描述 来自 ICPC CERC 1999/2000,有改动. 有 NNN 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词. ...

  9. codevs1580单词游戏

    题目描述中说: 单词为at,k=8则新单词为ib 推移规则是:如果k为正数则下推,否则上推,当推移超越边界时回到另一端继续推移. 但在我做题时发现: 这个描述与数据所要求的是完全相反的!!!! 样例1 ...

随机推荐

  1. react render渲染的几种情况

    1. 首次加载 2. setState改变组件内部state. 注意: 此处是说通过setState方法改变. 3. 接受到新的props

  2. web端手机方向传感器闲谈

    因为工作需要,这段时间接触的手机传感器比较多.总体来说,市场上的传感器表现参差不齐.IPhone在传感器表现方面卓越,而安卓由于什么机型都有,则显得差强人意. 首先还是说说怎么在web端调用手机传感器 ...

  3. 《前端面试加分项目》系列 企业级Vue瀑布流

    本文 GitHub github.com/ponkans/F2E 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习.文末有福利~~ 前言 接水怪又来 ...

  4. unittest实战(三):用例编写

    # coding:utf-8import unittestfrom selenium import webdriverimport timefrom ddt import ddt, data, unp ...

  5. 【echarts3】 折线图我踩过的那些坑 (tooltip 设置,line 单个点/散点不显示问题)

    echarts 折线图小技巧 echarts 折线图功能丰富且官方文档详细易懂,上手比较容易,这篇文章将分享一些项目中踩过的坑,示例主要以多条曲线为主,对大家完成一些 曲线.tooltip 和 mar ...

  6. 使用openxml提取word中的文本和图片并转为Html

    使用openxml提取word中的文本和图片 使用 openXml 提取 word 中的 Text 和 Drawing 使用 openXml 将 word 中的文本和图片转为Html 使用 openX ...

  7. 使用java短信验证

    package cn.geekss.util; import java.io.BufferedReader;import java.io.InputStreamReader;import java.i ...

  8. sonarqube配置全指南,集成阿里巴巴p3c规范

    环境准备 内置数据库 Sonar安装成功后,默认内置H2数据库,用于记录单次的扫描结果,对同一个project重复扫码,会覆盖之前的扫描记录,所以H2 数据库只应用于测试,不可以用于生产环境,那如果你 ...

  9. nginx显示静态html爆502 bad gateway的错误提示

    在centos的服务器上,没有启动php-fcgi. 本来是想设置显示一个静态文件目录的,用不着php,于是就关闭了php-fcgi. 结果打开爆了一个大大的nginx502 bad gateway的 ...

  10. Linux apache让网页编码错误

    今天帮一个小伙伴搞作业,遇到安装discuz乱码问题,就顺便在这里写一下,以供其他同学纠正. 开apache配置文件/etc/httpd/conf/httpd.conf 查找AddDefaultCha ...