【HDU3247】 Resource Archiver(DP+AC自动机+最短路)
Resource Archiver
Time Limit: 10000MS Memory Limit: 100000KB 64bit IO Format: %I64d & %I64u Description
Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a big one.
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.Input
There 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.Output
For each test case, print the length of shortest string.Sample Input
2 21110011110110010 0Sample Output
5
【题意】
给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒。问最小的长度为多少。
【分析】
良心题解:http://blog.csdn.net/woshi250hua/article/details/8021283

· 一开始要想到DP,这是最简单的一步。而且n很小明显是状压,再用一维记录一下最后一个拼接的串。
即d[i][j]表示现在已经拼接的串集合为i,最后一个串为j的最小费用。
转移方程->d[i+(1<<k-1)][k]=min{d[i+(1<<k-1)][k],d[i][j]+cost[j][k]}
转移方程是很容易想的,重点就是求cost[j][k]。
暴力的话,目测是10*10*1000*1000,有点慢- -。
所以,要用到优美的性质才行。
把两种串都建在AC自动机里,打上不同标记,然后按上面所说的沿着next向下走。
理解了很久这个沿着next向下走的过程之后,我觉得意思应该是这样:

a串和b串连接有很多种方式,其实可以转换成 -> 自己生成一个串,使得前缀是a串,后缀是b串。(如上图第一种情况)
之前做生成串的题目都是在图上沿nest走的,这样只要不走到危险节点,就不会出现病毒串(fail的优美性质)。
所以,我们就可以利用这种方法求出拼接且不含危险串的串了。
要让这个拼接串长度最小,也就是走的从a的末尾节点走到b的末尾节点的路程最小。(因为答案为a串长度+走的步数,而a串长度一定)
就是一个最短路。
其实感觉有一个小小的BUG,就是无论a,b串怎么拼都含病毒串,他会输出一个大于l[a]+l[b]的数,相当于在a、b串中乱填东西,使得不含病毒串(如上图第二种情况)。这样就与“拼接”的含义不符了。
你可以简单的判断一下之类的,但是我没有判断也A了。可能是正确的最优解覆盖了它的原因。
AC自动机要建60000不是50000。(一开始RE了~~)
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 60010
#define Maxl 1200
#define Mn 20
#define INF 0xfffffff
#define Mod 20090717 int n,m;
char s[Maxl]; struct node
{
// int cnt;
int fail,mark;
int son[];
}t[Maxn];int tot;
// int num;
int p[Mn],sl[Mn]; void upd(int x)
{
// t[x].cnt=0;
t[x].mark=;
memset(t[x].son,,sizeof(t[x].son));
} int mymin(int x,int y) {return x<y?x:y;}
int mymax(int x,int y) {return x>y?x:y;} void read_trie(int tk)
{
scanf("%s",s+);
int len=strlen(s+);
if(tk!=-) sl[tk]=len;
int now=;
for(int i=;i<=len;i++)
{
int ind=s[i]-''+;
if(!t[now].son[ind])
{
t[now].son[ind]=++tot;
upd(tot);
}
now=t[now].son[ind];
if(i==len)
{
if(tk==-) t[now].mark=-;
else t[now].mark=tk,p[tk]=now;
}
}
} queue<int > q;
void build_AC()
{
while(!q.empty()) q.pop();
q.push();
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=;i<=;i++)
{
if(t[x].son[i])
{
t[t[x].son[i]].fail=x?t[t[x].fail].son[i]:;
q.push(t[x].son[i]);
}
else t[x].son[i]=t[t[x].fail].son[i];
}
// t[x].mark+=t[t[x].fail].mark;
}
} int dis[Mn][Maxn];
bool inq[Mn];
void spfa(int x)
{
while(!q.empty()) q.pop();
memset(dis[x],,sizeof(dis[x]));
memset(inq,,sizeof(inq));
dis[x][p[x]]=;
q.push(p[x]);inq[p[x]]=;
while(!q.empty())
{
int now=q.front();
for(int i=;i<=;i++) if(t[t[now].son[i]].mark!=-)
{
if(dis[x][t[now].son[i]]>dis[x][now]+)
{
dis[x][t[now].son[i]]=dis[x][now]+;
if(!inq[t[now].son[i]])
{
inq[t[now].son[i]]=;
q.push(t[now].son[i]);
}
}
}
q.pop();inq[now]=;
}
}
void init()
{
tot=;upd();
for(int i=;i<=n;i++)
{
read_trie(i);
}
for(int i=;i<=m;i++) read_trie(-);
build_AC();
for(int i=;i<=n;i++)
{
spfa(i);
}
} bool check(int x,int y,int z)
{
// if(x==0&&y==0&&z==0) return 1;
// if(y==0||z==0) return 0;
if(((<<y-)&z)==) return ;
int h=;
for(int i=;i<=n;i++)
{
if((<<i-)&z) h++;
}
if(h==x) return ;
return ;
} int f[Maxl][Mn];
void dp()
{
memset(f,,sizeof(f));
// f[0][0]=0;
for(int i=;i<=n;i++) f[<<i-][i]=sl[i];
for(int i=;i<n;i++)
for(int j=;j<=n;j++)
for(int k=;k<=(<<n)-;k++) if(check(i,j,k))
{
if(f[k][j]>INF) continue;
for(int l=;l<=n;l++) if((k&(<<l-))==)
f[k+(<<l-)][l]=mymin(f[k+(<<l-)][l],f[k][j]+dis[j][p[l]]);
}
int ans=INF;
for(int i=;i<=n;i++) ans=mymin(ans,f[(<<n)-][i]);
printf("%d\n",ans);
} int main()
{
int kase=;
while()
{
scanf("%d%d",&n,&m);
if(n==&&m==) break;
init();
dp();
}
return ;
}
[HDU3247]
2016-07-13 09:55:14
【HDU3247】 Resource Archiver(DP+AC自动机+最短路)的更多相关文章
- HDU3247 Resource Archiver(AC自动机+BFS+DP)
题目,求最短的包含所有n个DNA片段且不包含任何一个病毒片段的序列. 容易用所有DNA片段和病毒片段建一个AC自动机,构造fail时处理一下各个结点后缀是DNA或者病毒的情况,然后dp[S][u]表示 ...
- HDU-3247 Resource Archiver(AC自动机+BFS)
Description Great! Your new software is almost finished! The only thing left to do is archiving all ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
- HDU3247 Resource Archiver —— AC自动机 + BFS最短路 + 状压DP
题目链接:https://vjudge.net/problem/HDU-3247 Resource Archiver Time Limit: 20000/10000 MS (Java/Others) ...
- 咕咕(数位dp+AC自动机)
咕咕(数位dp+AC自动机) 若一个字符串的字符集合是0~m-1,那么称它为m进制字符串.给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\).对于另一个m进制字符串\(S\),设\( ...
- 洛谷$P4045\ [JSOI2009]$密码 $dp$+$AC$自动机
正解:$dp$+$AC$自动机+搜索 解题报告: 传送门$QwQ$ 首先显然先建个$AC$自动机,然后考虑设$f_{i,j,k}$表示长度为$i$,现在在$AC$自动机的第$j$个位置,已经表示出来的 ...
- HDU3247 Resource Archiver (AC自动机+spfa+状压DP)
Great! Your new software is almost finished! The only thing left to do is archiving all your n resou ...
- HDU 3247 Resource Archiver (AC自己主动机 + BFS + 状态压缩DP)
题目链接:Resource Archiver 解析:n个正常的串.m个病毒串,问包括全部正常串(可重叠)且不包括不论什么病毒串的字符串的最小长度为多少. AC自己主动机 + bfs + 状态压缩DP ...
- 【hdu3247-Resource Archiver】位压DP+AC自动机+SPFA
题意:给定n个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. (2 <= n <= 10, 1 <= m <= 1000) 题 ...
随机推荐
- Day04 - Python 迭代器、装饰器、软件开发规范
1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...
- is_numeric漏洞分析
2014年,PHP中is_numeric函数十六进制绕过漏洞引发了一次安全问题 接下来,我们来分析一下这个漏洞的原理 函数介绍: is_numeric — 检测变量是否为数字或数字字符串. 函数原型: ...
- 基于bootstrap的datetimepicker插件
1.当时使用的资源地址:http://www.bootcss.com/p/bootstrap-datetimepicker/ 2.如何让时间只显示到日期,不显示具体时刻 控制显示精度的是datetim ...
- vs2010 Express 下载连接
记录: vs2010 Express 下载连接 正式下载链接: http://download.microsoft.com/download/5/C/1/5C156922-CA10-49D8-B7E ...
- C# 的可空合并运算符(??)到底是怎样的宝宝?
前言废语 也怪自己小白和不勤奋,没有系统的学习C#相关的东西,工作一年多还是初级小菜,深感不安,来到园子才发现好多钻研技术的人,也渐渐发现自己开始喜欢上了这个编程的世界.今日偶遇??操作符,发现我只看 ...
- C# 序列化和反序列
1.对象序列化的介绍 (1).NET支持对象序列化的几种方式 二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Seri ...
- Android 输入法键盘和activity页面遮挡问题解决
本文主要介绍Android中如何解决输入法键盘和activity页面遮挡的问题. 总结: 不希望遮挡设置activity属性android:windowSoftInputMode="adju ...
- Android SQLite ORM框架greenDAO在Android Studio中的配置与使用
博客: 安卓之家 微博: 追风917 CSDN: 蒋朋的家 简书: 追风917 博客园: 追风917 # 说明 greenDAO是安卓中处理SQLite数据库的一个开源的库,详情见其官网:我是官网 详 ...
- Microsoft SQL Server 管理 (常用管理及维护命令)
--查询当前连接的实例名 select @@servername --察看任何数据库属性 sp_helpdb master --设置单用户模式,同时立即断开所有用户 alter database No ...
- 2.RABBITMQ 入门 - WINDOWS - 生产和消费消息 一个完整案例
关于安装和配置,见上一篇 1.RABBITMQ 入门 - WINDOWS - 获取,安装,配置 公司有需求,要求使用winform开发这个东西(消息中间件),另外还要求开发一个日志中间件,但是也是要求 ...