HDU3247 Resource Archiver (AC自动机+spfa+状压DP)
Wait a minute… you realized that it isn’t as easy as you thought. Think about the virus killers. They’ll find your software suspicious, if your software contains one of the m predefined virus codes. You absolutely don’t want this to happen.
Technically, resource files and virus codes are merely 01 strings. You’ve already convinced yourself that none of the resource strings contain a virus code, but if you make the archive arbitrarily, virus codes can still be found somewhere.
Here comes your task (formally): design a 01 string that contains all your resources (their occurrences can overlap), but none of the virus codes. To make your software smaller in size, the string should be as short as possible.
InputThere will be at most 10 test cases, each begins with two integers in a single line: n and m (2 <= n <= 10, 1 <= m <= 1000). The next n lines contain the resources, one in each line. The next m lines contain the virus codes, one in each line. The resources and virus codes are all non-empty 01 strings without spaces inside. Each resource is at most 1000 characters long. The total length of all virus codes is at most 50000. The input ends with n = m = 0.OutputFor each test case, print the length of shortest string.Sample Input
2 2
1110
0111
101
1001
0 0
Sample Output
5
题解:AC自动机的fail指针跑spfa状压DP求最短串
总体思路是利用代码串和病毒串建立自动机,他们在自动机上的差别是一个末节点标记,一个不标记。然后将每个代码串尾节点看做图上的一个节点,利用自动机计算每个串其他所有串的不重叠的最短长度即两两节点间的最短距离。最后转变成TSP问题,状态压缩DP解之。
第一眼看到那个n,小等于10,soga,状态压缩,稍微思考下就能将问题转换成这样一个模型:n个串必须都选且选一次,求这n个串的排列使得组合成的串不包含病毒串并且长度最小。啊哈,这不是TSP问题吗?是的,你没有看错,转换成了TSP问题。
转换成TSP问题之后,我们想的是怎么让长度尽量小,考虑将两个代码串重叠起来。两个代码串a,b的前缀和后缀可能相等,他们组成的最短不包含病毒串的字符串c,前面部分为a,后面部分为b,这时候再来个d代码串要和前面两个合体,那么就成c和d的重叠问题了。
接下来我们要做的怎么让代码串a和代码串b组成的串c长度最小且不包含病毒串呢?我一开始用kmp来找两个串的相等前缀、后缀,然后组成串去ac自动机中匹配。然后一瞬间我就觉得我自己脑残了,这不是让ac自动机退化成kmp和字典树了吗!因为ac自动机上的一个节点到根的路径代表一个字符串,假设串a的末尾节是p,b的末尾节点是q,接着我们要做是在p点利用next数组转移到q,我们得到一个结论:从p到q所走的路径便是b除开与a重叠部分的那个后缀,如a为aaabb,b为bbaaa,那么路经就代表串b的aaa子串。我们怎么保证从p点走到q点,中间走过的路径表示的串一定是串b的后缀呢?两种情况:1、a是b的子串,这时候我们不会用到fail指针,显然可以 2、我们需要用到fail指针,每次用fail指针找到下一个匹配的位置假设是failx,failx节点到根节点所表示的串便是我们走过路径的最长后缀,这样一直找找到节点q,点q到根节点所表示的串遍是我们走过路径的最长后缀,然后上面的结论便得证。
总而言之,我们在ac自动机上走过的路径可以表示一个串,设为S,到达点p,那么点p到根节点这条路径所表示的串s,s为S的后缀。为用路径代表一个串是ac自动机优美之处。
我们从上面说的p点走到q点会有很多路径,要保证走过的路径长度最小即b串于a串的不重叠部分最短,要用到spfa,其实本题就退化成普通的Bfs,因为没有松弛操作。这样得到就可以得到各串相互之间的最短距离,然后就变成了很普通的TSP。
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define PI acos(-1.0)
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=;
const int maxnode=;
char s[maxn];
int n,m,tot,ans,ln[];
int pre[maxn],vis[maxnode],dis[][maxnode],dp[(<<)][];
int ch[maxnode][],link[maxnode],fail[maxnode],val[maxnode]; void Init()
{
tot=; ans=INF;
memset(ch[],,sizeof(ch[]));
} int GetId(char ch){return ch-'';} void Insert(int tk)
{
scanf("%s",s);
int len=strlen(s),u=;
if(tk!=-) ln[tk]=len;
for(int i=;i<len;++i)
{
int x=GetId(s[i]);
if(!ch[u][x])
{
memset(ch[tot],,sizeof(ch[tot]));
val[tot]=;
ch[u][x]=tot++;
}
u=ch[u][x];
}
if(tk==-) val[u]=-;
else val[u]=tk,pre[tk]=u;
} void GetFail()
{
queue<int> q;
q.push(); fail[]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=;i<=;++i)
{
if(ch[u][i])
{
fail[ch[u][i]] = u?ch[fail[u]][i]:;
q.push(ch[u][i]);
}
else ch[u][i]=ch[fail[u]][i];
}
}
} void spfa(int s)
{
memset(dis[s],INF,sizeof(dis[s]));
memset(vis,,sizeof(vis));
dis[s][pre[s]]=;
queue<int> q;
q.push(pre[s]);vis[pre[s]]=;
while(!q.empty())
{
int u=q.front();
for(int i=;i<=;++i)
{
if(val[ch[u][i]]!=-)
{
if(dis[s][ch[u][i]]>dis[s][u]+)
{
dis[s][ch[u][i]]=dis[s][u]+;
if(!vis[ch[u][i]])
{
vis[ch[u][i]]=;
q.push(ch[u][i]);
}
}
}
}
q.pop(); vis[u]=;
}
} bool check(int x,int y,int z)
{
if(((<<y-)&z)==) return false;
int num=;
for(int i=;i<=n;++i){ if((<<i-)&z) num++; }
return num==x? true:false;
} void work()
{
memset(dp,INF,sizeof(dp));
for(int i=;i<=n;++i) dp[(<<i-)][i]=ln[i];
for(int i=;i<n;++i)
{
for(int j=;j<=n;++j)
{
for(int k=;k<=(<<n)-;++k)
{
if(check(i,j,k))
{
for(int l=;l<=n;++l)
{
if((k&(<<l-)) == )
dp[k+(<<l-)][l]=min(dp[k+(<<l-)][l],dp[k][j]+dis[j][pre[l]]);
}
}
}
}
}
for(int i=;i<=n;++i) ans=min(ans,dp[(<<n)-][i]);
} int main()
{
while(scanf("%d%d",&n,&m)&&n&&m)
{
Init();
for(int i=;i<=n;++i) Insert(i);
for(int i=;i<=m;++i) Insert(-);
GetFail();
for(int i=;i<=n;++i) spfa(i);
work();
printf("%d\n",ans);
}
return ;
}
HDU3247 Resource Archiver (AC自动机+spfa+状压DP)的更多相关文章
- HDU - 3247 Resource Archiver (AC自动机,状压dp)
\(\quad\)Great! Your new software is almost finished! The only thing left to do is archiving all you ...
- HDU 3247 Resource Archiver (AC自动机+BFS+状压DP)
题意:给定 n 个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. 析:先把所有的文本串和病毒都插入到AC自动机上,不过标记不一样,可以给病毒标记-1, ...
- HDU3247 Resource Archiver —— AC自动机 + BFS最短路 + 状压DP
题目链接:https://vjudge.net/problem/HDU-3247 Resource Archiver Time Limit: 20000/10000 MS (Java/Others) ...
- Walk Through Squares HDU - 4758 AC自动机+简单状压DP
题意:给你两个串,求用m个R,n个D能组成多少个包含这两个串 题解:先构造一个AC自动机记录每个状态包含两个串的状态, 状态很容易定义 dp[i][j][k][status]表示在AC自动机K这个节点 ...
- bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)
数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...
- 【BZOJ-1097】旅游景点atr SPFA + 状压DP
1097: [POI2007]旅游景点atr Time Limit: 30 Sec Memory Limit: 357 MBSubmit: 1531 Solved: 352[Submit][Sta ...
- AC Challenge(状压dp)
ACM-ICPC 2018 南京赛区网络预赛E: 题目链接https://www.jisuanke.com/contest/1555?view=challenges Dlsj is competing ...
- Resource Archiver HDU - 3247 AC自动机+BFS+状压
题意: 给出n个资源串,m个病毒串,现在要如何连接资源串使得不含病毒串(可以重叠,样例就是重叠的). 题解: 这题的套路和之前的很不同了,之前的AC自动机+DP的题目一般都是通过teir图去转移, 这 ...
- 【BZOJ】1097: [POI2007]旅游景点atr(spfa+状压dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=1097 首先还是我很sb....想到了分层图想不到怎么串起来,,,以为用拓扑序搞转移,,后来感到不行. ...
随机推荐
- 一分钟带你学会利用mybatis-generator自动生成代码!
目录 一.MyBatis Generator简介 二.使用方式 三.实战 之前的文章<SpringBoot系列-整合Mybatis(XML配置方式)>介绍了XML配置方式整合的过程,本文介 ...
- HTML创建图像映射,布局,表单
来源: 实验楼 创建图像映射 在这之前我们动手试验过将图片作为链接来使用,触发链接的方式就是点击图片的任何地方都可以链接到跳转地址,有时我们需要实现,点击图片的不同地方跳转到不同的地方.意思就是,一张 ...
- SpringBoot 源码解析 (三)----- Spring Boot 精髓:启动时初始化数据
在我们用 springboot 搭建项目的时候,有时候会碰到在项目启动时初始化一些操作的需求 ,针对这种需求 spring boot为我们提供了以下几种方案供我们选择: ApplicationRunn ...
- go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数
温故知新不忘延迟基础 A "defer" statement invokes a function whose execution is deferred to the momen ...
- Python3.7.1学习(六)RabbitMQ在Windows环境下的安装
Windows下安装RabbitMQ 环境配置 部署环境 部署环境:windows server 2008 r2 enterprise(本文安装环境Win7) 官方安装部署文档:http://www. ...
- 在VMware通过挂载系统光盘搭建本地yum仓库
1.首先需要有一个VMware虚拟机: 2.进去虚拟机(这里用Linux下deCentOS进行演示): 3.用root账号进行登录,否则在根目录下没有一些操作权限: 4.打开终端: 5,输入命令“cd ...
- CSS RESET —— 浏览器样式重置
CSS Reset 1. CSS Reset为什么存在? 只要您的客户存在使用不同浏览器(ie,firefox,chrome等)的可能,那你就不得不从完美的理想状态回到现实,因为不同核心的浏览器对CS ...
- 你的文章里为什么不放源码Github链接了
"你的文章里为什么不放源码Github链接了?",一个读者这么问我 我把这张图发给了他,这是我之前放文章中Demo源码的Github仓库 他一脸疑惑,问我怎么了 经常使用Githu ...
- tomcat启动窗口出现乱码
tomcat启动窗口出现乱码 或者 idea运行服务器tomcat出现乱码 在tomcat的启动窗口打印的启动信息中包含了大量的中文乱码, 虽然这些对tomcat本身的使用没有任何影响,但却非 ...
- 2019-11-27:kali 2019-4中文乱码解决方法
1.更换阿里源 vim /etc/apt/soul,编辑源之后,apt-get updata && apt-get upgrade && apt-get clean , ...