题目链接:点击查看

题目大意:给出 n 个目标串和 m 个病毒串,要求构造出一个长度最短的,且包含全部 n 个目标串,但是不能包含任意一个病毒串的01字符串,输出其最短长度

题目分析:比较综合的一道题目了,以为是涉及到目标串和病毒串之间的关系,所以读完题目后不难想到先将这些字符串都扔到AC自动机里去,因为 n 非常小,所以可以考虑状态压缩,于是最初的想法就是壮压dp直接转移,dp[ state1 ][ state2 ] 代表着含有目标串状态为state1,且在AC自动机中的状态为state2时的最短长度,但非常遗憾的是,整个dp转移的时间复杂度达到了1024*50000*2,不出意外的话是会TLE的,所以我们必须想办法优化,稍微想一下的话不难发现,AC自动机中绝大部分的字符串都是病毒串的,也就是没有作用的结点,我们真正会用到的也只有那 n<=10 个结点,所以在建好AC自动机后,将可以代表目标串的结点单独拿出,因为之前的转移方程是:(设 i 为目标串的状态,j 为AC自动机的状态,nj 为接下来的状态,id[ i ]为AC自动机内结点 i 所代表的目标串状态)

dp[ i | id[ nj ] ][ nj ] = min( dp[ i | id[ nj ] ][ nj ] , dp[ i ][ j ] + 1 )

而现在的状态转移就变成了:

dp[ i | id[ nj ] ][ nj ] = min( dp[ i | id[ nj ] ][ nj ] , dp[ i ][ j ] + dis[ i ][ nj ] )

其中dis[ i ][ j ]代表着从状态 i 到状态 j 所需要添加的最少字符,到这里,我们就可以发现,因为dis[ i ][ j ]可以用bfs预处理得出,这样总的时间复杂度也就下降为了 1024*10*10 了

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;char s[N];int fail[N],id[N],trie[N][2],cnt;void insert_word(int _id)
{int len=strlen(s);int pos=0;for(int i=0;i<len;i++){int to=s[i]-'0';if(!trie[pos][to])trie[pos][to]=++cnt;pos=trie[pos][to];}id[pos]=_id;
}void getfail()
{queue<int>q;for(int i=0;i<2;i++){if(trie[0][i]){fail[trie[0][i]]=0;q.push(trie[0][i]);}}while(!q.empty()){int cur=q.front();q.pop();if(id[fail[cur]]<0)id[cur]=-1;elseid[cur]|=id[fail[cur]];for(int i=0;i<2;i++){if(trie[cur][i]){fail[trie[cur][i]]=trie[fail[cur]][i];q.push(trie[cur][i]);}elsetrie[cur][i]=trie[fail[cur]][i];}}
}vector<int>state;int dis[N],maze[15][15],dp[(1<<10)+100][15];void bfs(int pos)
{memset(dis,inf,sizeof(dis));queue<int>q;q.push(state[pos]);dis[state[pos]]=0;while(q.size()){int cur=q.front();q.pop();for(int i=0;i<2;i++){int nj=trie[cur][i];if(id[nj]<0)continue;if(dis[nj]>dis[cur]+1){dis[nj]=dis[cur]+1;q.push(nj);}}}for(int i=0;i<state.size();i++)maze[pos][i]=dis[state[i]];
}void init()
{cnt=0;memset(id,0,sizeof(id));memset(trie,0,sizeof(trie));state.clear();
}int main()
{
#ifndef ONLINE_JUDGE
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n,m;while(scanf("%d%d",&n,&m)!=EOF&&n+m){init();for(int i=0;i<n;i++){scanf("%s",s);insert_word((1<<i));}while(m--){scanf("%s",s);insert_word(-1);}getfail();state.push_back(0);for(int i=0;i<=cnt;i++)if(id[i]>0)state.push_back(i);for(int i=0;i<state.size();i++)bfs(i);memset(dp,inf,sizeof(dp));dp[0][0]=0;for(int i=0;i<(1<<n);i++){for(int j=0;j<state.size();j++){for(int k=0;k<state.size();k++){if(dp[i][j]!=inf){if(maze[j][k]==inf)continue;if(j==k)continue;dp[i|id[state[k]]][k]=min(dp[i|id[state[k]]][k],dp[i][j]+maze[j][k]);}}}}int ans=inf;for(int i=0;i<state.size();i++)ans=min(ans,dp[(1<<n)-1][i]);printf("%d\n",ans);    }return 0;
}

HDU - 3247 Resource Archiver(AC自动机+状压dp+bfs)相关推荐

  1. HDU - 2825 Wireless Password(AC自动机+状压dp)

    题目链接:点击查看 题目大意:给出 m 个匹配串,问长度为 n 的字符串中,至少包含 k 个匹配串(可重叠)的字符串有多少个 题目分析:考虑到n,m,k都特别小,所以可以先用AC自动机将状态关系转移出 ...

  2. HDU - 3247 Resource Archiver (AC自动机,状压dp)

    \(\quad\)Great! Your new software is almost finished! The only thing left to do is archiving all you ...

  3. HDU - 2825 Wireless Password (AC自动机 + 状压dp)

    题目链接 题意 求至少包含KKK个给定字符串长度为NNN的字符串 思路 把所有可能的字符串建AC自动机,遍历所有节点dp[i][j][k]dp[i][j][k]dp[i][j][k] 表示以节点jjj ...

  4. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  5. hdu 6086 Rikka with String(AC自动机+状压dp)

    题目链接:hdu 6086 Rikka with String 题意: 给你n个只含01的串,和一个长度L,现在让你构造出满足s[i]≠s[|s|−i+1] for all i∈[1,|s|] ,长度 ...

  6. HDU - 3341 Lost's revenge(AC自动机+状压dp)

    题目链接:点击查看 题目大意:给出 n 个模式串,最后给出一个匹配串,问如何重新排列匹配串,可以使得匹配串尽可能多的匹配模式串 题目分析:因为是模式串和匹配串的匹配,所以考虑AC自动机,因为数据范围比 ...

  7. AC自动机+状压dp hdu2825 Wireless Password

    传送门:点击打开链接 题意:有个密码长度为n,现在有m个魔力单词,要求密码中魔力单词的种类数>=k,问这种密码的种类数. 思路:和之前一样,我们会想到AC自动机去压缩状态,把状态给简化.然后我们 ...

  8. P4045-[JSOI2009]密码【AC自动机,状压dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4045 题目大意 给nnn个字符串,求有多少个长度为lll的字符串包含所有给出的字符串 解题思路 因为nnn很小, ...

  9. 【hdu2825】ac自动机 + 状压dp

    传送门 题目大意: 给你一些密码片段字符串,让你求长度为n,且至少包含k个不同密码片段串的字符串的数量. 题解: 因为密码串不多,可以考虑状态压缩 设dp[i][j][sta]表示长为i的字符串匹配到 ...

最新文章

  1. apache2.4中layout模块和ssi模块的冲突
  2. mysql数据库设计实践_MYSQL教程分享20个数据库设计的最佳实践
  3. tcl mysql_MySQL·TCL语言
  4. Android安全笔记-Tasks与Recents Screen与Fragment基本概念
  5. 音视频开发(29)---深入浅出理解视频编码H264结构
  6. Spring学习总结(8)——25个经典的Spring面试问答
  7. Struts 2的拦截器(Interceptor)总结
  8. Selenium常见异常分析及解决方案
  9. Detected problems with app native libraries (please consult log for detail): lib.so: text relocation
  10. 【第四章】详解Feign的实现原理
  11. 什么是网络安全网格?
  12. Windows下如何强制删除文件夹及文件的命令
  13. 计算机设计大赛英语怎么说,全国大学生计算机设计大赛国赛参赛指南
  14. 〖Python零基础入门篇㊿〗- Python中的 sys 模块
  15. 流媒体 - 02 常用命令(gst+ffmpeg+v4l2)
  16. Redis---客户端和服务端
  17. 数据结构与算法——广度和深度优先搜索
  18. c语言编程if,关于C语言中#if的用法
  19. 【D3.js 学习总结】12、D3布局-集群图
  20. 2020年卫星行业研究报告

热门文章

  1. turtle库是python的第三方库吗_turtle库的使用
  2. 顺序三元组 java_三元组顺序结构实现稀疏矩阵相加,行序优先(Java语言描述)
  3. MySQL 高级- 输出参数
  4. Feign-实现抽取
  5. 被丢弃的消息不能再次出现
  6. 初步认识Volatile-MESI优化带来的可见性问题
  7. AnnotationScopeMetadataResolver 解析作用域元数据
  8. 缓存-分布式锁-Redisson简介整合
  9. Redis工具类封装讲解和实战
  10. SpringBoot2.x整合redis实战讲解