题目描述

Io和Ao在玩一个单词游戏。

他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致。

游戏可以从任何一个单词开始。

任何单词禁止说两遍,游戏中只能使用给定词典中含有的单词。

游戏的复杂度定义为游戏中所使用的单词长度总和。

编写程序,求出使用一本给定的词典来玩这个游戏所能达到的游戏最大可能复杂度。

输入输出格式

输入格式:

输入文件的第一行,表示一个自然数N(1≤N≤16),N表示一本字典中包含的单词数量以下的每一行包含字典中的一个单词,每一个单词是由字母A、E、I、O和U组成的一个字符串,每个单词的长度将小于等于100,所有的单词是不一样的。

输出格式:

输出文件仅有一行,表示该游戏的最大可能复杂度。

输入输出样例

输入样例#1:
复制

5
IOO
IUUO
AI
OIOOI
AOOI
输出样例#1:
复制

16

题解

仔细观察就可以看出这是一张有向图,求最大无环路径权值

听说这是一个NP完全问题,看数据范围那么小想都没想就暴搜了,信心满满地T了,结果70分,想想卡了个时【就是搜索一定次数直接输出答案】竟然A了。。

但这不是正解。。。
正解:

状压dp
第一次接触状压dp是NOIP2016愤怒的小鸟QAQ
原来数据小的暴搜可以这样dp

同样的道理,我们设f[s][i]表示s状态下走到了i的最大权值【s是二进制数,每一位代表对应的点是否走过】
我们从0开始枚举s,对于每个点u,若s中包含了这个点u,那就可以看做走了那么多路径走到了u点,那么现在就可以从u点出发更新其他的点了
对于u出发的到达的点v,如果没有被访问过,就可以进行一次状态转移


f[s | (1 << v - 1)][v] = max(f[s | (1 << v - 1)][v],f[s][u] + d[u][v]);
由于新的状态的值一定比当前状态要大,所以这样做没有后效性,是可行的算法


暴搜卡时代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 20,maxm = 105,INF = 1000000000; inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
} char s[maxn][maxm];
int V[maxn],N,ans = 0;
bool vis[maxn]; int head[maxn],nedge = 0;
struct EDGE{
int to,next;
}edge[maxn * maxn]; inline void build(int a,int b){
edge[nedge] = (EDGE) {b,head[a]};
head[a] = nedge++;
} void init(){
fill(head,head + maxn,-1);
N = read();
REP(i,N){
scanf("%s",s[i]);
V[i] = strlen(s[i]);
}
REP(i,N) REP(j,N) if (i != j && s[i][V[i] - 1] == s[j][0]) build(i,j);
} int cnt = 0;
void dfs(int u,int sum){
cnt++;
if (cnt > 10000000){
cout<<ans<<endl;
exit(0);
}
vis[u] = true;
sum += V[u];
if (sum > ans) ans = sum;
Redge(u) if (!vis[edge[k].to]) dfs(edge[k].to,sum);
vis[u] = false;
} int main()
{
init();
REP(i,N) dfs(i,0);
cout<<ans<<endl;
return 0;
}


状压dp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 20,maxm = 1 << 16,INF = 1000000000; inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
} char s[maxn][105];
int d[maxn],f[maxm][maxn],N,ans = 0; void init(){
N = read();
REP(i,N){
scanf("%s",s[i]);
d[i] = strlen(s[i]) - 1;
}
} void solve(){
int maxv = (1 << N) - 1;
for (int i = 1; i <= N; i++)
f[1 << i - 1][i] = d[i] + 1;
for (int i = 0; i <= maxv; i++){
for (int j = 1; j <= N; j++){
int e1 = 1 << j - 1;
if ((i | e1) == i){
ans = max(ans,f[i][j]);
for (int k = 1; k <= N; k++){
int e2 = 1 << k - 1;
if (j != k && (i | e2) != i && s[j][d[j]] == s[k][0]){
f[i | e2][k] = max(f[i | e2][k],f[i][j] + d[k] + 1);
}
}
}
}
}
cout<<ans<<endl;
} int main()
{
init();
solve();
return 0;
}

洛谷 P1278 单词游戏 【状压dp】的更多相关文章

  1. 洛谷 P1278 单词游戏

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

  2. 洛谷P3959 宝藏(状压dp)

    传送门 为什么感觉状压dp都好玄学……FlashHu大佬太强啦…… 设$f_{i,j}$表示当前选的点集为$i$,下一次要加入的点集为$j$时,新加入的点和原有的点之间的最小边权.具体的转移可以枚举$ ...

  3. 洛谷 P3112 后卫马克 —— 状压DP

    题目:https://www.luogu.org/problemnew/show/P3112 状压DP...转移不错. 代码如下: #include<iostream> #include& ...

  4. 【洛谷4941】War2 状压Dp

    简单的状压DP,和NOIP2017 Day2 找宝藏 代码几乎一样.(比那个稍微简单一点) f[i][j] ,i代表点的状态,j是当前选择的点,枚举上一个选到的点k 然后从f[i-(1<< ...

  5. 洛谷 3959 宝藏——枚举+状压dp

    题目:https://www.luogu.org/problemnew/show/P3959 原来写了个不枚举起点的状压dp. #include<iostream> #include< ...

  6. 洛谷$P3959\ [NOIp2017]$ 宝藏 状压$dp$

    正解:状压$dp$ 解题报告: 传送门$QwQ$ $8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$ 发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j} ...

  7. 洛谷 P1433 吃奶酪 状压DP

    题目描述 分析 比较简单的状压DP 我们设\(f[i][j]\)为当前的状态为\(i\)且当前所在的位置为\(j\)时走过的最小距离 因为老鼠的坐标为\((0,0)\),所以我们要预处理出\(f[1& ...

  8. [洛谷P1278]单词游戏

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

  9. 洛谷P2473奖励关——状压DP

    题目:https://www.luogu.org/problemnew/show/P2473 还是对DP套路不熟悉... 像这种前面影响后面,而后面不影响前面的问题就应该考虑倒序递推: 看n只有15那 ...

随机推荐

  1. 搜索引擎ElasticSearch系列(五): ElasticSearch2.4.4 IK中文分词器插件安装

    一:IK分词器简介  IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本.最初,它是以开源 ...

  2. nmap保存结果

    nmap 192.168.0.2 -oX D:\myscan.xml 参数解释: -oN <filespec> (标准输出) -oX <filespec> (XML输出) -o ...

  3. Git生成SSH密钥

    git config --global user.name "yangjianliang"配置用户名 git config --global user.email "52 ...

  4. 第五篇 Postman离线安装interceptor插件---Chrome app及录制请求

    在测试中,总是苦恼于无法直接使用chrome浏览器的cookie等信息,终于在茫茫网海中,发现了 https://www.jianshu.com/p/a4223bab1e73, 感谢 智者向内寻求力量 ...

  5. header field token is not allowed by Access-Control-Allow-Headers in preflight response问题解决

    今天下午,本来打算使用aioxs在header里传一个token给后台服务器,如下图所示: 结果,控制台报了如下的错: 然后,我不停地百度,不停的改后台express的header设置,一直没有效果: ...

  6. zabbix_agentd-install.sh (脚本部署zabbix_agentd服务)

    原文发表于cu:2016-05-20 基于http://www.cnblogs.com/netonline/p/7406598.html(http://blog.chinaunix.net/uid-2 ...

  7. [转]oracle数据库定时任务dbms_job的用法详解

    这篇文章给大家详细介绍了dbms_job的用法,用于安排和管理作业队列,通过使用作业,可以使ORACLE数据库定期执行特定的任务.有需要的朋友们可以参考借鉴.   一.dbms_job涉及到的知识点 ...

  8. Factorials 阶乘(思维)

    Description N 的阶乘写作N!表示小于等于N的所有正整数的乘积.阶乘会很快的变大,如13!就必须用32位整数类型来存储,70!即使用浮点数也存不下了.你的任务是 找到阶乘最后面的非零位.举 ...

  9. TCP系列45—拥塞控制—8、SACK关闭的拥塞撤销与虚假快速重传

    一.概述 这篇文章介绍一下TCP从Recovery状态恢复到Open状态的时候cwnd的更新.我们在tcp重传部分的文章中曾经介绍过虚假重传的概念,Linux在探测到虚假重传的时候就会执行拥塞撤销操作 ...

  10. 虚拟机下安装CentOS6.5系统教程

    虚拟机下安装CentOS6.5系统教程 时间:2014-12-09 01:40来源:linuxdown.net 作者:linuxdown.net 举报 点击:15315次 其实通过VM安装虚拟机还是蛮 ...